TCP协议

        TCP/IP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket,从而在通信的两端之间形成虚拟的链路。一旦建立了虚拟的网络链接,两端的程序就可以通过虚拟的链路进行通信。Java对基于TCP协议的网络通信提供了良好的封装,使用Socket对象来代表两端的通信端口并通过Socket产生IO流来进行网络通信。

        TCP协议在通信时,需要建立独立的网络通路,并且还有重发机制:当一个通信实体发送一个消息给另一个通信实体时,需要收到另一个通信实体的确认消息,如果没收到则会再次重发。通过这种机制就很好的保证了通信的可靠。

        与UDP相比,TCP是面向连接的,很好的保证了通信的可靠性,但需要建立连接,并且还要两端互动;既消耗资源,又影响了通信速度(主要是要等待对方响应)。所以TCP多用于数据下载,文件传输等可靠性要求高的应用。

Socket类

        此类实现了客户端的套字节,也就是TCP通信的一个端点。使用Socket能方便简单的创建通信端,下面是Socket类的一些常用方法。

// 创建一个套接字,并自定IP地址和端口

Socket(InetAddress address, int port);  

Socket(String host, int port);

// 返回此套接字的连接地址

InetAddress getInetAddress();

// 返回此套接字的输入流

InputStream getInputStream();

// 返回此套接字的输出流

OutputStream getOutputStream();

// 用来标识输入流已完成了

void shutdownInput();

ServerSocket类

        此类实现服务器套接字,服务器套接字等待请求通过网络传入。也就是服务器建立一个通信终端,并且等待客户端的连接。使用ServerSocket类能方便快捷的创建一个服务器端点,下面是ServerSocket的一些常用方法。

// 创建绑定到特定端口的服务器套接字

ServerSocket(int port);

// 监听并接受到此套接字的连接

Socket accept(); 

TCP通信简单实例

        下面是一个简单的客户端与服务器端通信的实例,由于文件较多,先介绍下文件的结构与功能。

服务器端:

        MainServer类:服务器端程序启动入口,创建服务器套接字,创建并启动读写流线程,用来接收和发送数据;

        ServerInputThread类:服务器端输入流,读取客户端传来的数据;

        ServerOutputThread类:服务器端输出流,向客户端写数据;

客户端:

        MainClient类:客户端程序启动入口,创建客户端套接字,创建并启动读写流线程,用来接收和发送数据;

        ClientInputThread类:客户端输入流,读取服务器端传来的数据;

        ClientOutputThread类:客户端输出流,向服务器端写数据;

MainServer类

import java.net.ServerSocket;
import java.net.Socket;
public class MainServer {	
	public static void main(String args[]) throws Exception {
		ServerSocket serverSocket = new ServerSocket(5000);
		while(true) {
			// 一直处于监听状态,可以处理多个用户
			Socket socket = serverSocket.accept();
			// 启动读写线程
			new Thread(new ServerInputThread(socket)).start();
			new Thread(new ServerOutputThread(socket)).start();
		}
	}	
}

ServerInputThread类

import java.io.InputStream;
import java.net.Socket;
public class ServerInputThread implements Runnable {	
	private Socket socket;
	public ServerInputThread(Socket socket) {
		this.socket = socket;
	}
	@Override
	public void run() {
		try {
			// 获得输入流
			InputStream is = socket.getInputStream();
			while(true) {
				byte[] buffer = new byte[1024];
				int length = is.read(buffer);
				String str = new String(buffer, 0, length);
				System.out.println("服务器收到:" + str);
			}
		}
		catch(Exception e) {
			e.printStackTrace();
		}
	}	
}

ServerOutputThread类

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
public class ServerOutputThread implements Runnable {	
	private Socket socket;
	public ServerOutputThread(Socket socket) {
		this.socket = socket;
	}
	@Override
	public void run() {
		try {
			// 获得输出流
			OutputStream os = socket.getOutputStream();
			while(true) {
				BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
				String line = reader.readLine();
				os.write(line.getBytes());
			}
		}
		catch(Exception e) {
			e.printStackTrace();
		}
	}	
}

MainClient类

import java.net.Socket;
public class MainClient {
	public static void main(String args[]) throws Exception {		
		Socket socket = new Socket("192.168.20.138", 5000);		
		new Thread(new ClientInputThread(socket)).start();
		new Thread(new ClientOutputThread(socket)).start();		
	}	
}

ClientInputThread类

import java.io.InputStream;
import java.net.Socket;
public class ClientInputThread implements Runnable {	
	private Socket socket;
	public ClientInputThread(Socket socket) {
		this.socket = socket;
	}
	@Override
	public void run() {
		try {
			// 获得输入流
			InputStream is = socket.getInputStream();
			while(true) {
				byte[] buffer = new byte[1024];
				int length = is.read(buffer);
				String str = new String(buffer, 0, length);
				System.out.println("客户端收到:" + str);
			}
		}
		catch(Exception e) {
			e.printStackTrace();
		}
	}	
}

ClientOutputThread类

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
public class ClientOutputThread implements Runnable {
	private Socket socket; 
	public ClientOutputThread(Socket socket) {
		this.socket = socket;
	}
	@Override
	public void run() {
		try {
			// 获得输入流
			OutputStream os = socket.getOutputStream();
			while(true) {
				BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
				String line = reader.readLine();
				os.write(line.getBytes());
			}
		}
		catch(Exception e) {
			e.printStackTrace();
		}
	}
}

        在该例中对代码做了一定的封装与优化,把TCP通信的流程分到了不同的代码块中,看起来不是很清晰,下面就对TCP通信的流程做一个梳理,再结合上面的实例,希望能对TCP通信有个更深入的理解。

服务器端:

1、建立服务端套接字,例如:ServerSocket serverSocket = new ServerSocket(5000);

2、监听客户端请求,并建立连接,获取对应socket端点,例如:Socket socket = serverSocket.accept();

3、获取输入流对象,读取客户端的数据,例如:InputStream is = socket.getInputStream();

4、获取输出流对象,往客户端发送数据,例如:OutputStream os = socket.getOutputStream();

5、关闭资源;

客户端:

1、创建客户端socket端点,例如:Socket socket = new Socket("192.168.20.138", 5000);

2、获取输出流对象,往服务器端发送数据,例如:OutputStream os = socket.getOutputStream();

3、获取输入流对象,读取服务器端的数据,例如:InputStream is = socket.getInputStream();

4、关闭资源;