0


网络编程套接字

很容易搞混,得好好理理

1.网络编程的基本概念

①什么是网络编程:
网络编程,指网络上的主机,通过不同的进程,以编程的方式实现网络通信(或称为网络数据传输。

②请求和响应分别指的什么?
一般来说,获取一个网络资源,涉及到两次网络数据传输:
第一次:请求数据的发送
第二次:响应数据的发送。
举个例子:
请求和响应在生活中是很好理解的,我手机没电了向别人借一下手机就是一个请求,而别人的回应就是响应。

1.1服务器

在常见的网络数据传输场景下,把提供服务的一方进程,称为服务端(也称服务器),可以提供对外服务。通俗可以理解成供应者。

1.2客户端

获取服务的一方进程,称为客户端。通俗可以理解成获得者。

2.Socket套接字

2.1概念

Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。基于Socket套接字的网络程序开发就是网络编程。

2.2分类

①流套接字:(使用传输层TCP协议)

a.TCP的特点:

有连接,可靠,面向字节流,全双工

b.分别解释一下以上名词:

有连接:
需要连通,才能交换数据(比如打电话,需要你接了之后才能够和你进行通话)

可靠:
传输过程中发送方知道接收方有没有接收数据(打电话,接了电话那么就会接收到数据,否则就不知道是否接收了数据)

面向字节流:
以字节为单位进行传输的方式

全双工:
一条链路双向通信(无疑,无论是打电话还是发QQ都是一种双向的操作)

②数据报套接字:(使用传输层UDP协议)

a.UDP特点:

无连接,不可靠,面向数据报,全双工

b.分别解释一下以上名词:

无连接:
不需要连接,直接就能发送数据(比如发QQ,我不需要得到你的允许就可以直接给你发送)

不可靠:
不知道传输的对象有没有接收到信息(发QQ别人未回,我们不知道是已读还是未读)

面向数据报:
以数据报为单位进行传输,一次发送/接收都必须是完整的一个数据报或者多个数据报,不能是半个啊,一个半数据报这种

全双工:
一条链路双向通信(无疑,无论是打电话还是发QQ都是一种双向的操作)

③原始套接字

原始套接字用于自定义传输层协议,用于读写内核没有处理的IP协议数据。我们不学习原始套接字,简单了解即可。

3.UDP数据报套接字编程

对客户端发送请求,服务器接收请求并作出回应的过程图(这里是一次请求一次回应)

3.1DatagramPocket API

①什么是DatagramPocket?

DatagramPacket是UDP发送和接收的数据报。每次发送/接收数据,都在传输一个DatagramPocke对象

②DatagramPocket的构造方法:

方法签名
方法说明
DatagramPacket(byte[] buf, int length)

构造一个DatagramPacket以用来接收数据报,接收的数据保存在 字节数组(第一个参数buf)中,接收指定长度(第二个参数为length)

DatagramPacket(byte[]

buf, int offset, int length,

SocketAddress address)

构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从0到指定长度(第二个参数length)。address指定目的主机的IP和端口号

注意:

构造UDP发送的数据报时,需要传入 SocketAddress ,该对象可以使用 InetSocketAddress 来创建。

InetSocketAddress ( SocketAddress 的子类 )构造方法:

方法签名方法说明InetSocketAddress(InetAddress address, int port)创建一个Socket地址,包含IP地址和端口号③DatagramPocket的方法:
方法签名方法说明
InetAddress

getAddress()

从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址

int getPort()

从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号

byte[]getData()

获取数据报中的数据

3.2DatagramSocket API

①什么是DatagramSocket?

创建了一个UDP版本的Socket对象,实质上代表着操作系统中一个Socket文件(更进一步而言是对网卡进行的读写的操作)

②DatagramSocket的构造方法:
方法签名方法说明
DatagramSocket()

创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口(一般用于客户端)

DatagramSocket(int

port)

创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用于服务端)

③DatagramSocket的方法:
方法签名方法说明
void receive(DatagramPacket p)

从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待)

void send(DatagramPacket

p)

从此套接字发送数据报包(不会阻塞等待,直接发送)

void close()

关闭此数据报套接字

3.3UDP实现回显服务

①什么是回显服务?

请求的是啥,回应的就是啥的操作

②对回显服务进行代码实现:

相关注意事项注释中已经讲解得非常细了,这里只着重强调一个点

客户端:

  1. import java.io.IOException;
  2. import java.net.*;
  3. import java.util.Scanner;
  4. public class UDPClient {
  5. //首先需要有一个DataframSocket实例,这是进行网络编程的前提
  6. private DatagramSocket socket=null;
  7. private String serverIP;//IP地址,这里是指服务器传过来的
  8. private int serverPort;//端口号,这里是指服务器传过来的
  9. public UDPClient(String Ip,int port) throws SocketException {
  10. socket = new DatagramSocket();
  11. //这里就是用无参版本的构造socket对象,就是让系统随机分配一个端口号
  12. serverIP=Ip;//这个指定的是服务器的IP地址和端口号和客户端没有关系
  13. serverPort=port;
  14. }
  15. public void start() throws IOException {
  16. Scanner input= new Scanner(System.in);
  17. while (true){
  18. //首先先从控制台读取到用户输入的信息,然后才能发送
  19. System.out.println("->");
  20. String request = input.next();
  21. //然后把用户写的信息构造成一个UDP请求,才能发送,指定IP和端口号,才知道传到了哪个服务器去
  22. DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length,
  23. InetAddress.getByName(serverIP),serverPort);
  24. //然后发送UDP数据报
  25. socket.send(requestPacket);
  26. //发送完之后需要再接收从服务器得到的响应数据
  27. //这里仍然需要用一个字节类数组来对返回内容进行接收
  28. DatagramPacket responsePacket = new DatagramPacket(new byte[1024],1024);
  29. socket.receive(responsePacket);
  30. //然后再把响应的数据写成字符串形式,然后打印到控制台
  31. String response = new String(responsePacket.getData(),0,responsePacket.getLength(),"UTF-8");
  32. System.out.printf("req:%s,resp:%s\n",request,response);
  33. }
  34. }
  35. public static void main(String[] args) throws IOException {
  36. UDPClient udpClient=new UDPClient("127.0.0.1",3030);
  37. udpClient.start();
  38. }
  39. }

服务器:

  1. import java.io.IOException;
  2. import java.net.DatagramPacket;
  3. import java.net.DatagramSocket;
  4. import java.net.SocketException;
  5. public class UDPServer {
  6. //首先需要有一个DataframSocket实例,这是进行网络编程的前提
  7. private DatagramSocket socket = null;
  8. public UDPServer(int port) throws SocketException {
  9. //这个地方会出现异常的原因
  10. //1.端口号已经被占用了,同一主机的两个程序不能有相同的端口号
  11. //2.2.每个进程能打开的文件个数是有上限的,资源耗尽后是打不开的
  12. socket=new DatagramSocket(port);
  13. }
  14. public void start() throws IOException {
  15. System.out.println("启动服务器!");
  16. //由于UDP的不可靠性,因此可以直接接收从客户端传来的数据,不用进行连接
  17. while(true){
  18. //这个时候就需要等待客户端发来请求,进行接收并作出回应
  19. //因为服务器本身就是被动接收数据的,而不是发送
  20. //构造一个Datagrampocket来对数据报进行发送和接收
  21. // 且接收应该用一个空的byte类型的数组对内容来进行接收(这是DatagramPocket的一个构造方法)
  22. DatagramPacket requestPacket=new DatagramPacket(new byte[1024],1024);
  23. //当没有接收到客户端的请求时,receive()就会阻塞,直到接收到才停止阻塞
  24. socket.receive(requestPacket);
  25. //接收到客户端的请求后需要作出回应
  26. //此时已经将接收到的数据放在requestPacket里面了,然后将这里面的数据解析出来,解析成字符串
  27. //new String()方法可以将字符,字节转换为字符串
  28. String request=new String(requestPacket.getData(),0,requestPacket.getLength(),"UTF-8");//也可以指定字符编码
  29. //解析后需要找到一个新的字符串来进行存放,并产生相应
  30. String response = prcoess(request);
  31. //对客户端作出响应
  32. //这里不仅要放回响应内容,而且要指定好要发送到的IP地址和端口号
  33. DatagramPacket responsePacket=new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());
  34. //发送过来的是DatagramPacket数据报,返回的也就是这样的数据报,但是发送回去的就不再是一个空的了,而是应该把从上面所得到的响应字符串放到里面然后
  35. socket.send(responsePacket);
  36. //可以再手动输出一下客户端的IP地址和端口号
  37. System.out.printf("[%s:%d] req: %s, resp: %s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);
  38. }
  39. }
  40. public String prcoess(String request){
  41. return request;
  42. }
  43. public static void main(String[] args) throws IOException {
  44. UDPServer udpServer=new UDPServer(3030);
  45. udpServer.start();
  46. }
  47. }

③一个简单翻译程序的实现(代码):

客户端没有更改,只是把服务器进行了调整

  1. package UDP;
  2. import java.io.IOException;
  3. import java.net.SocketException;
  4. import java.util.HashMap;
  5. public class UDPdictServer extends UDPServer {
  6. private HashMap<String,String> dict=new HashMap<>();
  7. public UDPdictServer(int port) throws SocketException {
  8. super(port);
  9. dict.put("cat", "小猫");
  10. dict.put("dog", "小狗");
  11. dict.put("fuck", "卧槽");
  12. dict.put("pig", "小猪");
  13. }
  14. @Override
  15. public String prcoess(String request) {
  16. return dict.getOrDefault(request, "该词无法被翻译!");
  17. }
  18. public static void main(String[] args) throws IOException {
  19. UDPdictServer server = new UDPdictServer(3030);
  20. server.start();
  21. }
  22. }

4.TCP流套接字编程

关于TCP的执行过程图

4.1ServerSocket API

①什么是ServerSocket?

ServerSocket 是创建TCP服务端Socket的API。

②ServerSocket的方法:
方法签名方法说明
Socket accept()

开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接,否则阻塞等待

void close()
关闭此套接字

4.2Socket API

①什么是Socket?

Socket 是客户端Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端Socket。

②Socket的构造方法:

方法签名方法说明
Socket(String host, int port)

创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接

③Socket的方法:
方法签名方法说明
InetAddress getInetAddress()

返回套接字所连接的地址

InputStream getInputStream()

返回此套接字的输入流

OutputStream getOutputStream()

返回此套接字的输出流

4.3TCP实现回显服务

代码实现:(相关细节内容在代码注解中讲得很详细)

客户端:

  1. package TCP;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import java.io.OutputStream;
  5. import java.io.PrintWriter;
  6. import java.net.Socket;
  7. import java.util.Scanner;
  8. public class TCPClient {
  9. private Socket socket=null;
  10. public TCPClient(String serverIP,int serverPort) throws IOException {
  11. //对于UDP的socket和TCP的serverSocket来说,构造函数里面给定的端口号,就是指定自己要绑定哪个端口号
  12. //而这里对于TCP的Socket来说,这里指定的IP和端口号是表示自己要与哪一个服务器进行连接,这里的IP和端口号都是服务器的
  13. //调用这个构造方法就会和服务器进行连接,就会使accept的立马进行接通
  14. socket = new Socket(serverIP,serverPort);
  15. }
  16. //启动客户端
  17. public void start() throws IOException {
  18. System.out.println("和服务器连接成功!");
  19. Scanner input = new Scanner(System.in);
  20. //因为TCP是流来传输运行的
  21. try(InputStream inputStream=socket.getInputStream()){
  22. try(OutputStream outputStream=socket.getOutputStream()){
  23. while(true){//此时仍然是需要四个步骤
  24. //1.从控制台读取字符串
  25. System.out.println("从控制台读取到的字符串->");
  26. //客户端要输入请求
  27. String request=input.next();
  28. // 2. 根据读取的字符串,将所读的字符串构造为请求, 把请求发给服务器
  29. //用printWriter来对读取的内容进行接收
  30. PrintWriter printWriter = new PrintWriter(outputStream);
  31. printWriter.println(request);
  32. printWriter.flush(); // 如果不刷新, 可能服务器无法及时看到数据.
  33. //3.读取到服务器来的响应,并对其写入的内容进行解析
  34. //然后从服务器中读取响应,并解析
  35. Scanner respScanner = new Scanner(inputStream);
  36. String response = respScanner.next();
  37. //打印先关结果
  38. System.out.printf("req:%s,resp:%s\n",request,response);
  39. }
  40. }
  41. } catch (IOException e) {
  42. e.printStackTrace();
  43. }
  44. }
  45. public static void main(String[] args) throws IOException {
  46. TCPClient tcpClient=new TCPClient("127.0.0.1",9090);
  47. tcpClient.start();
  48. }
  49. }

服务器:

  1. package TCP;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import java.io.OutputStream;
  5. import java.io.PrintWriter;
  6. import java.net.ServerSocket;
  7. import java.net.Socket;
  8. import java.util.Scanner;
  9. public class TCPServer {
  10. private ServerSocket serverSocket = null;
  11. public TCPServer(int port) throws IOException {
  12. serverSocket=new ServerSocket(port);//给服务器指定端口号
  13. }
  14. public void start() throws IOException {
  15. System.out.println("服务器启动");
  16. while(true){
  17. // 由于 TCP 是有连接的, 不能一上来就读数据, 而要先建立连接. (接电话)
  18. // accept 就是在 "接电话", 接电话的前提是, 有人给你打了, 如果当前没有客户端尝试建立连接, 此处的 accept 就会阻塞.
  19. // accept 返回了 一个 socket 对象, 称为 clientSocket. 后续和客户端之间的沟通, 都是通过 clientSocket 来完成的.
  20. // 进一步讲, serverSocket 就干了一件事, 接电话
  21. //进一步来说是建立了连接然后应答上,用clientSocket来进行后续操作
  22. Socket clientSocket = serverSocket.accept();
  23. //对接收的响应进行处理
  24. processConnection(clientSocket);
  25. }
  26. }
  27. public void processConnection(Socket clientSocket) throws IOException {
  28. //IP地址和端口来进行打印
  29. System.out.printf("[%s,%d] 客户端建立连接\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
  30. //对客户端发来的请求进行响应处理
  31. // 这里的针对 TCP socket 的读写就和文件读写是一致的
  32. try(InputStream inputStream=clientSocket.getInputStream()){
  33. try(OutputStream outputStream=clientSocket.getOutputStream()) {
  34. // 循环的处理每个请求, 分别返回响应
  35. Scanner input = new Scanner(inputStream);
  36. while(true){
  37. //读取请求
  38. //已经读取完,不会再输入新的内容
  39. while(!input.hasNext()){
  40. //返回客户端的ip地址以及端口号
  41. System.out.printf("[%s:%d] 客户端断开连接!\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
  42. break;
  43. }
  44. // 此处用 Scanner 更方便. 如果不用 Scanner 就用原生的 InputStream 的 read 也是可以的
  45. //对请求进行处理
  46. String request=input.next();
  47. // 2. 根据请求, 计算响应
  48. String response = process(request);
  49. // 3. 把这个响应返回给客户端
  50. // 为了方便起见, 可以使用 PrintWriter 把 OutputStream 包裹一下
  51. //读取返回响应所输入的内容用printWriter包裹,返回
  52. PrintWriter printWriter = new PrintWriter(outputStream);
  53. printWriter.println(response);
  54. // 刷新缓冲区, 如果没有这个刷新, 可能客户端就不能第一时间看到响应结果.
  55. printWriter.flush();
  56. //并打印出客户端的地址,端口号,以及请求和响应的内容
  57. System.out.printf("[%s:%d] req: %s, resp: %s\n", clientSocket.getInetAddress().toString(),
  58. clientSocket.getPort(), request, response);
  59. }
  60. }
  61. }catch (IOException e) {
  62. e.printStackTrace();
  63. } finally {
  64. // 要关闭,因为资源时有限的,一个服务器不止为1个客户端进行服务,用了之后要及时关闭
  65. try {
  66. clientSocket.close();
  67. } catch (IOException e) {
  68. e.printStackTrace();
  69. }
  70. }
  71. }
  72. public String process(String request){
  73. return request;
  74. }
  75. public static void main(String[] args) throws IOException {
  76. TCPServer tcpServer=new TCPServer(9090);
  77. tcpServer.start();
  78. }
  79. }

结果如下:

此时我们会发现,如果是一个客户端的话,与服务器之间的连接是没有问题的,如果是多个客户端,就不能够进行连接。那这到底是为什么呢?

但是显然在我们实际中,这样是不可取的,大大浪费了服务器的资源,所以我们引入了线程池,或者多线程来解决这个问题,代码如下。

4.3.1用多线程进行优化

代码如下:(对服务器部分进行修改)

  1. package TCP;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import java.io.OutputStream;
  5. import java.io.PrintWriter;
  6. import java.net.ServerSocket;
  7. import java.net.Socket;
  8. import java.util.Scanner;
  9. public class TCPServer {
  10. private ServerSocket serverSocket = null;
  11. public TCPServer(int port) throws IOException {
  12. serverSocket=new ServerSocket(port);//给服务器指定端口号
  13. }
  14. public void start() throws IOException {
  15. System.out.println("服务器启动");
  16. while(true){
  17. // 由于 TCP 是有连接的, 不能一上来就读数据, 而要先建立连接. (接电话)
  18. // accept 就是在 "接电话", 接电话的前提是, 有人给你打了, 如果当前没有客户端尝试建立连接, 此处的 accept 就会阻塞.
  19. // accept 返回了 一个 socket 对象, 称为 clientSocket. 后续和客户端之间的沟通, 都是通过 clientSocket 来完成的.
  20. // 进一步讲, serverSocket 就干了一件事, 接电话
  21. //进一步来说是建立了连接然后应答上,用clientSocket来进行后续操作
  22. Socket clientSocket = serverSocket.accept();
  23. //使用多线程:
  24. Thread t = new Thread(()->{
  25. try {
  26. processConnection(clientSocket);//这样之后每一个客户端的连接就从串行变成并行的了,然后每一个客户端的连接就可以成功了
  27. } catch (IOException e) {
  28. e.printStackTrace();
  29. }
  30. });
  31. t.start();
  32. }
  33. }
  34. public void processConnection(Socket clientSocket) throws IOException {
  35. //IP地址和端口来进行打印
  36. System.out.printf("[%s,%d] 客户端建立连接\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
  37. //对客户端发来的请求进行响应处理
  38. // 这里的针对 TCP socket 的读写就和文件读写是一致的
  39. try(InputStream inputStream=clientSocket.getInputStream()){
  40. try(OutputStream outputStream=clientSocket.getOutputStream()) {
  41. // 循环的处理每个请求, 分别返回响应
  42. Scanner input = new Scanner(inputStream);
  43. while(true){
  44. //读取请求
  45. //已经读取完,不会再输入新的内容
  46. while(!input.hasNext()){
  47. //返回客户端的ip地址以及端口号
  48. System.out.printf("[%s:%d] 客户端断开连接!\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
  49. break;
  50. }
  51. // 此处用 Scanner 更方便. 如果不用 Scanner 就用原生的 InputStream 的 read 也是可以的
  52. //对请求进行处理
  53. String request=input.next();
  54. // 2. 根据请求, 计算响应
  55. String response = process(request);
  56. // 3. 把这个响应返回给客户端
  57. // 为了方便起见, 可以使用 PrintWriter 把 OutputStream 包裹一下
  58. //读取返回响应所输入的内容用printWriter包裹,返回
  59. PrintWriter printWriter = new PrintWriter(outputStream);
  60. printWriter.println(response);
  61. // 刷新缓冲区, 如果没有这个刷新, 可能客户端就不能第一时间看到响应结果.
  62. printWriter.flush();
  63. //并打印出客户端的地址,端口号,以及请求和响应的内容
  64. System.out.printf("[%s:%d] req: %s, resp: %s\n", clientSocket.getInetAddress().toString(),
  65. clientSocket.getPort(), request, response);
  66. }
  67. }
  68. }catch (IOException e) {
  69. e.printStackTrace();
  70. } finally {
  71. // 要关闭,因为资源时有限的,一个服务器不止为1个客户端进行服务,用了之后要及时关闭
  72. try {
  73. clientSocket.close();
  74. } catch (IOException e) {
  75. e.printStackTrace();
  76. }
  77. }
  78. }
  79. public String process(String request){
  80. return request;
  81. }
  82. public static void main(String[] args) throws IOException {
  83. TCPServer tcpServer=new TCPServer(9090);
  84. tcpServer.start();
  85. }
  86. }

4.3.2用线程池进行优化

对服务器代码进行修改:

  1. package TCP;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import java.io.OutputStream;
  5. import java.io.PrintWriter;
  6. import java.net.ServerSocket;
  7. import java.net.Socket;
  8. import java.util.Scanner;
  9. import java.util.concurrent.*;
  10. public class TCPServer {
  11. private ServerSocket serverSocket = null;
  12. public TCPServer(int port) throws IOException {
  13. serverSocket=new ServerSocket(port);//给服务器指定端口号
  14. }
  15. public void start() throws IOException {
  16. System.out.println("服务器启动");
  17. ExecutorService pool=Executors.newCachedThreadPool();
  18. while(true){
  19. // 由于 TCP 是有连接的, 不能一上来就读数据, 而要先建立连接. (接电话)
  20. // accept 就是在 "接电话", 接电话的前提是, 有人给你打了, 如果当前没有客户端尝试建立连接, 此处的 accept 就会阻塞.
  21. // accept 返回了 一个 socket 对象, 称为 clientSocket. 后续和客户端之间的沟通, 都是通过 clientSocket 来完成的.
  22. // 进一步讲, serverSocket 就干了一件事, 接电话
  23. //进一步来说是建立了连接然后应答上,用clientSocket来进行后续操作
  24. Socket clientSocket = serverSocket.accept();
  25. //对接收的响应进行处理
  26. //通过线程池来实现
  27. pool.submit(new Runnable() {
  28. @Override
  29. public void run() {
  30. try {
  31. processConnection(clientSocket);
  32. } catch (IOException e) {
  33. e.printStackTrace();
  34. }
  35. }
  36. });
  37. }
  38. }
  39. public void processConnection(Socket clientSocket) throws IOException {
  40. //IP地址和端口来进行打印
  41. System.out.printf("[%s,%d] 客户端建立连接\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
  42. //对客户端发来的请求进行响应处理
  43. // 这里的针对 TCP socket 的读写就和文件读写是一致的
  44. try(InputStream inputStream=clientSocket.getInputStream()){
  45. try(OutputStream outputStream=clientSocket.getOutputStream()) {
  46. // 循环的处理每个请求, 分别返回响应
  47. Scanner input = new Scanner(inputStream);
  48. while(true){
  49. //读取请求
  50. //已经读取完,不会再输入新的内容
  51. while(!input.hasNext()){
  52. //返回客户端的ip地址以及端口号
  53. System.out.printf("[%s:%d] 客户端断开连接!\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
  54. break;
  55. }
  56. // 此处用 Scanner 更方便. 如果不用 Scanner 就用原生的 InputStream 的 read 也是可以的
  57. //对请求进行处理
  58. String request=input.next();
  59. // 2. 根据请求, 计算响应
  60. String response = process(request);
  61. // 3. 把这个响应返回给客户端
  62. // 为了方便起见, 可以使用 PrintWriter 把 OutputStream 包裹一下
  63. //读取返回响应所输入的内容用printWriter包裹,返回
  64. PrintWriter printWriter = new PrintWriter(outputStream);
  65. printWriter.println(response);
  66. // 刷新缓冲区, 如果没有这个刷新, 可能客户端就不能第一时间看到响应结果.
  67. printWriter.flush();
  68. //并打印出客户端的地址,端口号,以及请求和响应的内容
  69. System.out.printf("[%s:%d] req: %s, resp: %s\n", clientSocket.getInetAddress().toString(),
  70. clientSocket.getPort(), request, response);
  71. }
  72. }
  73. }catch (IOException e) {
  74. e.printStackTrace();
  75. } finally {
  76. // 要关闭,因为资源时有限的,一个服务器不止为1个客户端进行服务,用了之后要及时关闭
  77. try {
  78. clientSocket.close();
  79. } catch (IOException e) {
  80. e.printStackTrace();
  81. }
  82. }
  83. }
  84. public String process(String request){
  85. return request;
  86. }
  87. public static void main(String[] args) throws IOException {
  88. TCPServer tcpServer=new TCPServer(9090);
  89. tcpServer.start();
  90. }
  91. }

最后用TCP实现一个翻译功能(服务器作出一定修改,客户端不改)

  1. package TCP;
  2. import java.io.IOException;
  3. import java.net.Socket;
  4. import java.util.HashMap;
  5. public class TcpDictSever extends TCPServer{
  6. private HashMap<String,String> map = new HashMap<>();
  7. public TcpDictSever(int port) throws IOException {
  8. super(port);
  9. map.put("cat","猫");
  10. map.put("pig","猪");
  11. map.put("dog","狗");
  12. }
  13. @Override
  14. public String process(String request) {
  15. return map.getOrDefault(request,"当前词组无法找到!");
  16. }
  17. public static void main(String[] args) throws IOException {
  18. TcpDictSever tcpDictSever=new TcpDictSever(9090);
  19. tcpDictSever.start();
  20. }
  21. }

感谢观看~

标签: 网络 tcp/ip 服务器

本文转载自: https://blog.csdn.net/weixin_58850105/article/details/124442614
版权归原作者 红苹果超好吃 所有, 如有侵权,请联系我们删除。

“网络编程套接字”的评论:

还没有评论