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、关闭资源;