TCP协议:如何实现客户端和服务器端的交流?

Source

实例:超简陋版人工AI对答程序

一、描述:

在客户端输入问题,服务器端将给出答案。

二、代码示例

1.客户端 

步骤:

  • 首先创建一个Scanner对象input,用于从控制台读取用户输入的问题。用户输入的一行文本将存储在question字符串变量中。

  • 接着尝试创建一个Socket对象clientSocket,连接到本地主机的 8848 端口,建立与服务器的连接。同时创建BufferedWriter对象writerBufferedReader对象reader,分别用于向服务器发送数据和从服务器接收数据。

  • 使用writerquestion中的问题数据写入到Socket的输出流,并通过flush方法确保数据立即发送。

  • 调用shutdownOutput方法关闭Socket的输出流,表示客户端数据发送完毕。

  • 使用readerSocket的输入流中读取服务器返回的一行回答数据,并存储在ans字符串变量中。

  • 最后将服务器端的回答打印输出到控制台。

  • 如果在上述的输入输出操作或网络连接过程中发生IOException异常,将打印异常的堆栈跟踪信息,用于错误排查。

package com.XXX;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;

//人工智障对答程序(客户端)
public class AIzzClient {
	public static void main(String[] args) {
		try (Scanner input = new Scanner(System.in)) {
			//读取控制台输入的问题
			String question = input.nextLine();
			//创建Socket、输出值、输入值
			try (Socket clientSocket = new Socket(InetAddress.getLocalHost(),8848);
					BufferedWriter writer = new BufferedWriter(
							new OutputStreamWriter(clientSocket.getOutputStream()));
					BufferedReader reader = new BufferedReader(
							new InputStreamReader(clientSocket.getInputStream()))) {
				//向服务器端发送"问题"(输出至服务器端)
				writer.write(question);
				writer.flush();
				
				//暂时关闭输出流
				clientSocket.shutdownOutput();
				
				//接受服务器端返回的"答案"
				String ans = reader.readLine();
				System.out.println("来自服务器端的回答:"+ ans);
				
			} catch (IOException e) {
				e.printStackTrace();
			}
				
		}
	}
}

2.服务器端

步骤 

  • 在类中首先定义了一个静态的HashMap对象map,用于存储问题与答案的对应关系。

  • main方法中,首先创建一个ServerSocket对象serverSocket,并绑定到端口 8848,用于监听客户端的连接请求。
  • 进入一个无限循环,使用serverSocket.accept()方法等待并接受客户端的连接请求,连接成功后会返回一个Socket对象clientSocket
  • 获取连接的客户端的 IP 地址,并存储在clientIp变量中。
  • 然后分别创建BufferedReader对象readerBufferedWriter对象writer,用于读取客户端发送的问题和向客户端发送问题的答案。
  • 使用reader.readLine()方法读取客户端发送的问题,并将其存储在question变量中。如果读取到的问题为空或者长度为 0,则跳过本次循环。
  • 根据读取到的问题,在map中查找对应的答案,并将其存储在answer变量中。如果在map中未找到对应的问题,将answer设置为“对不起,我不知道您在说什么?”。
  • 使用writer.write()方法将问题的答案发送给客户端。
  • 如果在上述的输入输出操作或网络连接过程中发生IOException异常,将打印异常的堆栈跟踪信息,用于错误排查和调试。
package com.XXX;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;

//人工智障对答程序(服务器端)
public class AIzzServer {
	private static HashMap<String,String> map = new HashMap<String,String>();
	static {
		map.put("你好", "你好呀,孙子");
		map.put("hi", "hello,孙子");
		map.put("hello", "hi,孙子");
		map.put("吃了吗", "没呢,孙子");
		map.put("很高兴认识你", "我也是哦");

	}
	public static void main(String[] args) {
		try(ServerSocket serverSocket = new ServerSocket(8848)){
			while(true) {
				Socket clientSocket = serverSocket.accept();
				String clientIp = clientSocket.getInetAddress().getHostAddress();
				//输入流:读取客户端发送的"问题"
				//输出流:发送问题的答案给客户端
				try(BufferedReader reader = new BufferedReader(
						new InputStreamReader(clientSocket.getInputStream()));//输入流(读)
				BufferedWriter writer = new BufferedWriter(//输出流(写)
						new OutputStreamWriter(clientSocket.getOutputStream()));){
					//读取例子客户端的“问题”
					String question = reader.readLine();
					if(question==null || question.length()==0) {
						continue;
					}
					
					System.out.printf("来自客户端[%s]的问题:%s\n",clientIp,question);
					
					String answer = map.get(question);
					answer = answer==null ? "对不起,我不知道您在说什么?":answer;
					
					//将问题的答案输出至"客户端"
					writer.write(answer);
				}
			}		
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

3.运行结果

图1  正确示例运行结果

图2  错误示例运行结果