在TCP Socket编程中,客户端有多个,而服务器端只有一个,由客户端TCP向服务器端TCP发送连接请求,服务器端的ServerSocket实例则监听来自客户端的TCP连接请求,并为每个请求创建新的Socket实例
由于服务端在调用accept()等待客户端的连接请求时会阻塞,直到收到客户端发送的连接请求才会继续往下执行代码,因此要为每个Socket连接开启一个线程。服务器端要同时处理ServerSocket实例和Socket实例,而客户端只需要使用Socket实例。
另外,每个Socket实例会关联一个InputStream和OutputStream对象,通过OutputStream来发送数据,并通过从InputStream来接收数据。.
简单来说,使用TCP方式进行网络通讯时,需要建立专门的虚拟连接,然后进行可靠的数据传输,如果数据发送失败,则客户端会自动重发该数据
由于TCP需要建立专用的虚拟连接以及确认传输是否正确,所以使用TCP方式的速度稍微慢一些,而且传输时产生的数据量要比UDP稍微大一些。
在实际的网络编程中,一般重要的数据使用TCP方式进行数据传输,因为它能够确保接收方完全正确地获取发送方所发送的全部数据 。非重要的数据可以使用UDP方式传递。因为它是不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方。
TCP建立链接的步骤
客户端向服务器端发送连接请求,被动地等待服务器的响应, 通过I/O流与服务端通信
服务端的建立一个通信终端,被动地等待客户端的连接。
当客户端向服务端发生连接请求后,服务端创建一个sockt实例,并为该实例创建一个新的线程,使用I/O 流与客户端进行通讯
TCP客户端创建步骤
- 创建一个Socket实例 指定远程主机的ip和端口,建立一个TCP连接
- 通过I/O流与服务端通信
- 当不需要连接的时候,使用Socket类的close来关闭连接
具体代码实现如下:
/**
*
* @param serverIp 服务端 IP
* @param serverPort 服务端端口
* @param msg 发生的消息
* @throws IOException
*/
public static void client(String serverIp, int serverPort, String msg) throws IOException {
String response = null;
//与端口进行连接
Socket socket = new Socket(serverIp, serverPort);
socket.setSoTimeout(5000);
PrintStream out = new PrintStream(socket.getOutputStream());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out.println(msg);
try {
response = bufferedReader.readLine();
System.out.println("接收到服务端消息:"+response);
} catch (SocketTimeoutException e) {
System.out.println("连接超时,无响应");
}
if (socket != null) {
//如果构造函数建立起了连接,则关闭套接字,如果没有建立起连接,自然不用关闭
socket.close(); //只关闭socket,其关联的输入输出流也会被关闭
}
}
TCP服务端创建步骤:
创建一个ServerSocket实例并指定本地端口,用来监听客户端在该端口发送的TCP连接请求
当接收客户端TCP 请求后
- 调用ServerSocket的accept()方法以获取客户端连接,并通过其返回值创建一个Socket实例
- 为返回的Socket实例开启新的线程,并使用Socket实例的I/O流与客户端通信
当通信结束,可以使用Socket的close()方法关闭该客户端连接
当连接终止后,调用ServerSocket close 方法,关闭服务端
具体实现代码:
/**
* 这个类主要是为了用来创建Sockt 实例
*/
public class TcpServerThread implements Runnable {
private Socket socketClient = null;
String responseToClient = "你好客户端";
public TcpServerThread(Socket socketClient) {
this.socketClient = socketClient;
}
public void run() {
try {
//获取Socket的输出流,用来向客户端发送数据
PrintStream out = new PrintStream(socketClient.getOutputStream());
//获取Socket的输入流,用来接收从客户端发送过来的数据
BufferedReader buf = new BufferedReader(new InputStreamReader(socketClient.getInputStream()));
boolean flag = true;
while (flag) {
//接收从客户端发送过来的数据
String str = buf.readLine();
if (str == null || "".equals(str)) {
flag = false;
} else {
//将接收到的字符串前面加上echo,发送到对应的客户端
System.out.println("接受到客户端消息客户端消息:" + str);
out.println(":" + responseToClient);
}
}
out.close();
socketClient.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
* @param port 服务器端口
* @throws Exception
*/
public static void tcpServer(int port)throws Exception{
ServerSocket serverSocket =new ServerSocket(port);
Socket socketClient=null;
boolean flag=true;
while (flag){
socketClient=serverSocket.accept();
System.out.println("与客户端连接成功");
new Thread(new TcpServerThread(socketClient)).start();
}
serverSocket.close();
}