[本文是自己学习所做笔记,欢迎转载,但请注明出处:http://blog.csdn.net/jesson20121020]
网络上的两个程序通过一个双向的通讯连接实现数据的交互,这个双向链路的一端称为一个Socket。Socket通常用来实现客户方和服务方的连接。Socket是TCP/IP协议的一个十分流行的编程界面,一个Socket由一个IP地址和一个端口号唯一确定。
在传统的UNIX环境下可以操作TCP/IP协议的接口不止Socket一个,Socket所支持的协议种类不光是TCP/IP一种,因此两者之间没有必然的联系。在java环境下,Socket编主要是基于TCP/IP协议的网络编程。
使用Socket进行Client/Server程序设计的一般连接过程是这样的:Server端Listen(监听)某个端口是否有连接请求,Client端向Server端发回Connect(连接请求), Server端向Client端发回Accept(接受)消息。一个连接就建立起来了。Server端和Client端都可以通过Send,Write等方法与对方通信。
对于一个功能齐全的Socket,都要包含以下基本结构,其工作过程包含以下四个基本的步骤:
(1). 创建Socket;
(2). 打开连接到Socket的输入/出流。
(3). 按照一定的协议对Socket进行读/写操作。
(4). 关闭Socket。
java在java.net中提供了两个类Socket和ServerSocket,分别用来表示双向连接的客户端和服务端。这是两个封装得非常好的类,使用很方便,构造方法如下:
Socket(); Socket(Proxy proxy); Socket(InetAddress address,int port); Socket(InetAddress address,int port,boolean stream); Socket(String host,int port); Socket(String host,int port,boolean stream); Socket(SocketInmpl impl); Socket(String host,int port,InetAddress localAddr,int localPort); Socket(InetAddress address,int port,InetAddress localAddr,int localPort); ServerSocket(); ServerSocket(int port); ServerSocket(int port,int backup); ServerSocket(int port,int backup,InetAddress bindAddr);
其中,address,host和port分别是双向连接中另一方的ip地址,主机名和端口号,stream指明socket是流socket还是数据报socket,localPort表示本地主机的端口号,localAddr和bindAddr是本地机器的的地址,impl是socket的父类,既可以用来创建serverSocket又可以用来创建Socket。如:
Socket client = new Socket("127.0.0.1",2000);
ServerSocket server = new ServerSocket(2000);
注意,在选择端口时,需要小心,每个端口提供的一种特定的服务,只有给出正确的端口,才能获得相应的服务,0~1023为系统保留,如http服务端口号80,telent服务端口号21,所以我们在选择端口时,最好选择一个大于1023的数,以防止冲突。
如果,客户端与服务端均采用单线程实现通信,则每次双方只能发送一条信息,即按:client发-server收-server发-client收.......这种模式进行通讯,可以观察下列单线程实现代码输出结果:
客户端代码SocketTalkClient.java:
package com.jesson.mianshi.network; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class SocketTalkClient { /** * @param args */ public static void main(String[] args) { SocketTalkClient client = new SocketTalkClient(); // 测试单线程实现的客户端与服务端交互 System.out.println("client: 单线程........"); client.singleThreadTalkClient(); } /** * 单线程实现的客户端与服务端通信 */ public void singleThreadTalkClient() { try { Socket socket = new Socket("127.0.0.1", 4700); // 向本机的4700端口发出客户请求 BufferedReader sin = new BufferedReader(new InputStreamReader( System.in)); // 由系统标准输入设备构造BufferedReader对象 PrintWriter os = new PrintWriter(socket.getOutputStream()); // 由Socket对象得到输出流,并构造PrintWriter对象 BufferedReader is = new BufferedReader(new InputStreamReader( socket.getInputStream())); // 由Socket对象得到输入流,并构造相应的BufferedReader对象 String readline; readline = sin.readLine(); // 从系统标准输入读入一字符串 while (!readline.equals("bye")) { os.println(readline); // 将从系统标准输入读入的字符串输出到Server os.flush(); // 刷新输出流,使Server马上收到该字符串 System.out.println("Client: " + readline); try { System.out.println("Server: " + is.readLine()); } catch (IOException e) { readline = sin.readLine(); continue; } readline = sin.readLine(); // 从系统标准输入读入一字符串 } // 继续循环 os.close(); // 关闭Socket输出流 is.close(); // 关闭Socket输入流 socket.close(); // 关闭Socket } catch (Exception e) { System.out.println("error"); } } }
package com.jesson.mianshi.network; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class SocketTalkServer { public static void main(String[] args) { SocketTalkServer server = new SocketTalkServer(); // 测试单线程实现的客户端与服务端交互 System.out.println("server: 单线程........"); server.singleThreadTalkServer(); } /** * 单线程实现的客户端与服务端通信 */ public void singleThreadTalkServer() { ServerSocket server = null; try { server = new ServerSocket(4700); } catch (IOException e) { // TODO Auto-generated catch block System.out.println("can not listen to:" + e); } Socket socket = null; try { socket = server.accept(); } catch (IOException e) { // TODO Auto-generated catch block System.out.println("can not accept socket from client:" + e); } String line; try { BufferedReader is = new BufferedReader(new InputStreamReader( socket.getInputStream())); PrintStream os = new PrintStream(socket.getOutputStream()); BufferedReader sin = new BufferedReader(new InputStreamReader( System.in)); System.out.println("client: " + is.readLine()); line = sin.readLine(); while (!line.equals("bye")) { os.println(line); os.flush(); System.out.println("Server: " + line); System.out.println("Client: " + is.readLine()); line = sin.readLine(); } os.close(); is.close(); socket.close(); server.close(); } catch (IOException e) { // TODO Auto-generated catch block System.out.println("error: " + e); } } }程序执行输出结果:
客户端输出:
client: 单线程........ hello server Client: hello server Server: hello cient 我每次只能发送一条消息 Client: 我每次只能发送一条消息 Server: 我也是
服务端输出:
<span style="font-size:14px;">server: 单线程........ client: hello server hello cient Server: hello cient Client: 我每次只能发送一条消息 我也是 Server: 我也是</span>
可以看出,用单线程实现,客户端每次只能发送一条消息,要实现双方都可以发送任意条消息,这就需要用到多个线程了,这里用了两个线程来实现监听和写。代码如下:
客户端代码(SocketTalkClient.java):
package com.jesson.mianshi.network; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class SocketTalkServer { public static void main(String[] args) { SocketTalkServer server = new SocketTalkServer(); // 测试多线程实现的客户端与服务端交互 System.out.println("server: 多线程........"); server.MultiThreadTalkServer(); } /** * 多线程实现的客户端与服务端交互 */ private void MultiThreadTalkServer() { ServerSocket server = null; try { server = new ServerSocket(4701); } catch (IOException e) { // TODO Auto-generated catch block System.out.println("can not listen to:" + e); } Socket socket = null; try { socket = server.accept(); } catch (IOException e) { // TODO Auto-generated catch block System.out.println("can not accept socket from client:" + e); } String line; try { BufferedReader is = new BufferedReader(new InputStreamReader( socket.getInputStream())); PrintWriter os = new PrintWriter(socket.getOutputStream()); BufferedReader sin = new BufferedReader(new InputStreamReader( System.in)); new ServerLinstenThread(is).start(); new ServerWriteThread(sin, os).start(); /* * os.close(); is.close(); socket.close(); server.close(); */ } catch (IOException e) { // TODO Auto-generated catch block System.out.println("error: " + e); } } /** * 服务端听线程 * * @author jesson * */ class ServerLinstenThread extends Thread { private BufferedReader linsten; public ServerLinstenThread(BufferedReader linsten) { // TODO Auto-generated constructor stub this.linsten = linsten; } public void run() { // TODO Auto-generated method stub String clientInfo; try { while (true) { clientInfo = linsten.readLine(); System.out.println("Client: " + clientInfo); if (clientInfo.equals("bye")) { System.out.println("Client下线,程序退出"); System.exit(0); } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * 服务端端写线程 * * @author jesson * */ class ServerWriteThread extends Thread { private BufferedReader writer; private PrintWriter printWriter; public ServerWriteThread(BufferedReader writer, PrintWriter printWriter) { this.writer = writer; this.printWriter = printWriter; } public void run() { // TODO Auto-generated method stub String serverInfo; try { while (true) { serverInfo = writer.readLine(); printWriter.println(serverInfo); printWriter.flush(); System.out.println("Server: " + serverInfo); if (serverInfo.equals("bye")) { System.out.println("Server自己下线,程序退出"); System.exit(0); } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }服务端代码(SocketTalkServer.java):
package com.jesson.mianshi.network; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class SocketTalkServer { public static void main(String[] args) { SocketTalkServer server = new SocketTalkServer(); // 测试多线程实现的客户端与服务端交互 System.out.println("server: 多线程........"); server.MultiThreadTalkServer(); } /** * 多线程实现的客户端与服务端交互 */ private void MultiThreadTalkServer() { ServerSocket server = null; try { server = new ServerSocket(4701); } catch (IOException e) { // TODO Auto-generated catch block System.out.println("can not listen to:" + e); } Socket socket = null; try { socket = server.accept(); } catch (IOException e) { // TODO Auto-generated catch block System.out.println("can not accept socket from client:" + e); } String line; try { BufferedReader is = new BufferedReader(new InputStreamReader( socket.getInputStream())); PrintWriter os = new PrintWriter(socket.getOutputStream()); BufferedReader sin = new BufferedReader(new InputStreamReader( System.in)); new ServerLinstenThread(is).start(); new ServerWriteThread(sin, os).start(); /* * os.close(); is.close(); socket.close(); server.close(); */ } catch (IOException e) { // TODO Auto-generated catch block System.out.println("error: " + e); } } /** * 服务端听线程 * * @author jesson * */ class ServerLinstenThread extends Thread { private BufferedReader linsten; public ServerLinstenThread(BufferedReader linsten) { // TODO Auto-generated constructor stub this.linsten = linsten; } public void run() { // TODO Auto-generated method stub String clientInfo; try { while (true) { clientInfo = linsten.readLine(); System.out.println("Client: " + clientInfo); if (clientInfo.equals("bye")) { System.out.println("Client下线,程序退出"); System.exit(0); } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * 服务端端写线程 * * @author jesson * */ class ServerWriteThread extends Thread { private BufferedReader writer; private PrintWriter printWriter; public ServerWriteThread(BufferedReader writer, PrintWriter printWriter) { this.writer = writer; this.printWriter = printWriter; } public void run() { // TODO Auto-generated method stub String serverInfo; try { while (true) { serverInfo = writer.readLine(); printWriter.println(serverInfo); printWriter.flush(); System.out.println("Server: " + serverInfo); if (serverInfo.equals("bye")) { System.out.println("Server自己下线,程序退出"); System.exit(0); } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
执行上述代码,运行结果:
客户端输出:
client: 多线程........ 你好,server Client: 你好,server Server: 你好,client Server: server发送多条信息: Server: 1. abcd Server: 2. 1234 Server: 3. ABC client发送多条消息: Client: client发送多条消息: 1. xxxxx Client: 1. xxxxx 2.yyyy Client: 2.yyyy 3.zzzz Client: 3.zzzz bye Client: bye Client自己下线,程序退出
server: 多线程........ Client: 你好,server 你好,client Server: 你好,client server发送多条信息: Server: server发送多条信息: 1. abcd Server: 1. abcd 2. 1234 Server: 2. 1234 3. ABC Server: 3. ABC Client: client发送多条消息: Client: 1. xxxxx Client: 2.yyyy Client: 3.zzzz Client: bye Client下线,程序退出
原文地址:http://blog.csdn.net/jesson20121020/article/details/45111813