1.TCP Socket在Java上的实现
Java 为 TCP 协议提供了两个类:Socket 类和 ServerSocket 类。一个 Socket 实例代表了TCP 连接的一端。一个 TCP 连接(TCP connection)是一条抽象的双向信道,两端分别由 IP地址和端口号确定。在开始通信之前,要建立一个 TCP 连接,这需要先由客户端 TCP 向服务器端 TCP 发送连接请求。ServerSocket 实例则监听 TCP 连接请求,并为每个请求创建新的 Socket 实例。也就是说,服务器端要同时处理 ServerSocket 实例和 Socket 实例,而客户端只需要使用 Socket 实例。每个Socket实例会关联一个InputStream和OutputStream对象,我们通过将字节写入套接字的OutputStream来发送数据,并通过从InputStream来接收数据。
2.TCP连接的建立步骤
客户端向服务器端发送连接请求后,就被动地等待服务器的响应。典型的TCP客户端要经过下面三步操作:
1、创建一个Socket实例:构造函数向指定的远程主机和端口建立一个TCP连接;
2.通过套接字的I/O流与服务端通信;
3、使用Socket类的close方法关闭连接。
服务端的工作是建立一个通信终端,并被动地等待客户端的连接。典型的TCP服务端执行如下两步操作:
1、创建一个ServerSocket实例并指定本地端口,用来监听客户端在该端口发送的TCP连接请求;
2、重复执行:
1)调用ServerSocket的accept()方法以获取客户端连接,并通过其返回值创建一个Socket实例;
2)为返回的Socket实例开启新的线程,并使用返回的Socket实例的I/O流与客户端通信;
3)通信完成后,使用Socket类的close()方法关闭该客户端的套接字连接
3.TCP Demo
Demo1.基本的流发送示例:
服务端开启一个TCP服务器,参数为端口号
客户端启动一个TCP服务,参数为服务端的地址,发送的字符,端口号
1 import java.net.Socket; 2 import java.net.SocketException; 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.OutputStream; 6 7 public class TCPClient { 8 9 public static void main(String[] args) throws IOException { 10 11 if ((args.length < 2) || (args.length > 3)) 12 13 throw new IllegalArgumentException( 14 "Parameter(s):<Server> <Word> [<Port>]"); 15 16 String server = args[0]; // Server name or IP address 17 /* Convert argument String to bytes using the default character encoding */ 18 byte[] senddata = args[1].getBytes(); 19 int servPort = (args.length == 3) ? Integer.parseInt(args[2]) : 7; 20 /* Create socket that is connected to server onspecified port*/ 21 Socket socket = new Socket(server, servPort); 22 System.out.println("Connected to server...sending echo string"); 23 24 InputStream in = socket.getInputStream(); 25 OutputStream out = socket.getOutputStream(); 26 out.write(senddata); // Send the encoded string to the server 27 28 int totalBytesRcvd = 0; // Total bytes received so far 29 byte[] recvdata = new byte[in.available()]; 30 int bytesRcvd; // Bytes received in last read 31 while (totalBytesRcvd < recvdata.length) { 32 if ((bytesRcvd = in.read(recvdata, totalBytesRcvd, recvdata.length 33 - totalBytesRcvd)) == -1) 34 throw new SocketException("Connection closed prematurely"); 35 totalBytesRcvd += bytesRcvd; 36 } // data array is full 37 38 System.out.println("Received: " + new String(recvdata)); 39 40 socket.close(); // Close the socket and its streams 41 } 42 }
1 import java.net.*; // for Socket, ServerSocket, andInetAddress 2 import java.io.*; // for IOException and Input/OutputStream 3 4 public class TCPServer { 5 6 private static final int BUFSIZE = 32; // Size of receivebuffer 7 8 public static void main(String[] args) throws IOException { 9 10 if (args.length != 1) // Test for correct # of args 11 throw new IllegalArgumentException("Parameter(s): <Port>"); 12 13 int servPort = Integer.parseInt(args[0]); 14 15 /* Create a server socket to accept client connection requests */ 16 ServerSocket servSock = new ServerSocket(servPort); 17 18 int recvMsgSize; // Size of received message 19 byte[] receiveBuf = new byte[BUFSIZE]; // Receive buffer 20 21 while (true) { // Run forever, accepting and servicing connections 22 23 Socket clntSock = servSock.accept(); // Get client connection 24 25 SocketAddress clientAddress = clntSock.getRemoteSocketAddress(); 26 27 System.out.println("Handling client at " + clientAddress); 28 29 InputStream in = clntSock.getInputStream(); 30 OutputStream out = clntSock.getOutputStream(); 31 32 /* Receive until client closes connection, indicated by -1 return*/ 33 34 while ((recvMsgSize = in.read(receiveBuf)) != -1) { 35 36 out.write(receiveBuf, 0, recvMsgSize); 37 } 38 clntSock.close(); // Close the socket. We are done with this client! 39 } 40 /* NOT REACHED */ 41 42 } 43 }
Demo2.
客户端从控制台输入字符串,发送到服务端
服务端受到客户端的字符串后,加上部分信息(echo字符串)返回到客户端
1 package zyb.org.client; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 import java.io.PrintStream; 7 import java.net.Socket; 8 import java.net.SocketTimeoutException; 9 10 public class Client { 11 public static void main(String[] args) throws IOException { 12 //客户端请求与本机在20006端口建立TCP连接 13 Socket client = new Socket("127.0.0.1", 20006); 14 client.setSoTimeout(10000); 15 //获取键盘输入 16 BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); 17 //获取Socket的输出流,用来发送数据到服务端 18 PrintStream out = new PrintStream(client.getOutputStream()); 19 //获取Socket的输入流,用来接收从服务端发送过来的数据 20 BufferedReader buf = new BufferedReader(new InputStreamReader(client.getInputStream())); 21 boolean flag = true; 22 while(flag){ 23 System.out.print("输入信息:"); 24 String str = input.readLine(); 25 //发送数据到服务端 26 out.println(str); 27 if("bye".equals(str)){ 28 flag = false; 29 }else{ 30 try{ 31 //从服务器端接收数据有个时间限制(系统自设,也可以自己设置),超过了这个时间,便会抛出该异常 32 String echo = buf.readLine(); 33 System.out.println(echo); 34 }catch(SocketTimeoutException e){ 35 System.out.println("Time out, No response"); 36 } 37 } 38 } 39 input.close(); 40 if(client != null){ 41 //如果构造函数建立起了连接,则关闭套接字,如果没有建立起连接,自然不用关闭 42 client.close(); //只关闭socket,其关联的输入输出流也会被关闭 43 } 44 } 45 }
1 package zyb.org.server; 2 3 import java.net.ServerSocket; 4 import java.net.Socket; 5 6 public class Server { 7 public static void main(String[] args) throws Exception{ 8 //服务端在20006端口监听客户端请求的TCP连接 9 ServerSocket server = new ServerSocket(20006); 10 Socket client = null; 11 boolean f = true; 12 while(f){ 13 //等待客户端的连接,如果没有获取连接 14 client = server.accept(); 15 System.out.println("与客户端连接成功!"); 16 //为每个客户端连接开启一个线程 17 new Thread(new ServerThread(client)).start(); 18 } 19 server.close(); 20 } 21 }
1 package zyb.org.server; 2 3 import java.io.BufferedReader; 4 import java.io.InputStreamReader; 5 import java.io.PrintStream; 6 import java.net.Socket; 7 8 /** 9 * 该类为多线程类,用于服务端 10 */ 11 public class ServerThread implements Runnable { 12 13 private Socket client = null; 14 public ServerThread(Socket client){ 15 this.client = client; 16 } 17 18 @Override 19 public void run() { 20 try{ 21 //获取Socket的输出流,用来向客户端发送数据 22 PrintStream out = new PrintStream(client.getOutputStream()); 23 //获取Socket的输入流,用来接收从客户端发送过来的数据 24 BufferedReader buf = new BufferedReader(new InputStreamReader(client.getInputStream())); 25 boolean flag =true; 26 while(flag){ 27 //接收从客户端发送过来的数据 28 String str = buf.readLine(); 29 if(str == null || "".equals(str)){ 30 flag = false; 31 }else{ 32 if("bye".equals(str)){ 33 flag = false; 34 }else{ 35 //将接收到的字符串前面加上echo,发送到对应的客户端 36 out.println("echo:" + str); 37 } 38 } 39 } 40 out.close(); 41 client.close(); 42 }catch(Exception e){ 43 e.printStackTrace(); 44 } 45 } 46 47 }
参考文章:
【Java TCP/IP Socket】TCP Socket(含代码) http://blog.csdn.net/ns_code/article/details/14105457
《Java TCP/IP Socket 编程》