您的位置:首页 > 新闻 > 会展 > 网站推广资讯_郴州网页设计招聘_关键词推广_网络技术培训

网站推广资讯_郴州网页设计招聘_关键词推广_网络技术培训

2024/12/27 17:21:25 来源:https://blog.csdn.net/Themberfue/article/details/144615079  浏览:    关键词:网站推广资讯_郴州网页设计招聘_关键词推广_网络技术培训
网站推广资讯_郴州网页设计招聘_关键词推广_网络技术培训

这里是Themberfue

        在上一节中,我们简单认识了 TCP协议 和 UDP协议 以及 基于UDP Socket 编写了简单的网络通信代码

        本节我们将基于 TCP Socket 编写简单的网络通信代码


TCP Socket 

        类似 UDP Socket,Java也基于 TCP协议 进行了一些接口的封装

        基于 TCP 封装的 SocketAPI:

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

方法签名方法说明
ServerSocket(int port)创建⼀个服务端流套接字Socket,并绑定到指定端⼝

        ServerSocket提供的方法

方法签名方法说明
Socket accept()开始监听指定端口(创建时绑定的端⼝),有客户端连接后,返回⼀个服务端Socket对象,并基于该 Socket建立与客户端的连接,否则阻塞等待
void close()关闭此套接字

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

方法签名方法说明
Socket(String host, int port)创建⼀个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接

        Socket提供的方法

方法签名方法说明
InetAddressgetInetAddress()返回套接字所连接的地址
InputStreamgetInputStream()返回此套接字的输入流
OutputStreamgetOutputStream()返回此套接字的输出流

代码编写与讲解 

TcpEchoServer

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** @author: Themberfue* @date: 2024/11/14 19:24* @description:*/
public class TcpEchoServer {// TCP 协议专门用于创建服务端的对象private ServerSocket socket = null;// 这里和 UDP 服务器类似,也是在构造对象时,绑定端口号public TcpEchoServer(int port) throws IOException {this.socket = new ServerSocket(port);}public void start() throws IOException {System.out.println("启动服务器");// 这种情况一般不会用 fixedThreadPool,不然处理客户端请求的数量就固定了ExecutorService executorService = Executors.newCachedThreadPool();// 需要一直执行里面的逻辑// 一直保持去连接客户端的状态while (true) {// 对于 TCP 来说,需要先处理和客户端发来的连接(有连接)// 通过读写 clientSocket,与客户端进行通信// 如果没有客户端发起连接,那么就阻塞在 accept// 这里的阻塞和多线程的阻塞有本质区别// 如果只是一个线程处理连接和读取请求两个工作// 该线程会在 hasNext() 那里阻塞,就不能处理下一个客户端的连接了// 所以引入多线程来处理,这里的主线程处理与客户端的连接// 连接到一个客户端后,就创建一个线程来处理客户端发送来的请求Socket clientSocket = socket.accept();//            Thread t = new Thread(() -> {
//                processConnection(clientSocket);
//            });
//            t.start();// 反复创建的线程,开销还是很大的,所以使用线程池来处理请求更高效executorService.submit(() -> {processConnection(clientSocket);});}}// 处理一个客户端的连接// 可能涉及到多个客户端的请求和响应private void processConnection(Socket clientSocket) {// 建立连接成功后,打印客户端上线,表示与客户端建立连接System.out.printf("[%s:%d]:客户端上线\n", clientSocket.getInetAddress(), clientSocket.getPort());// TCP 是通过面向字节流的try (OutputStream outputStream = clientSocket.getOutputStream();InputStream inputStream = clientSocket.getInputStream()) {// 针对 OutputStream 套了一层PrintWriter printWriter = new PrintWriter(outputStream);// 针对 InputStream 套了一层Scanner scanner = new Scanner(inputStream);// 这里也是反复执行,一个客户端可能发来多次请求while (true) {// 若该客户端关闭后,表示不会发送请求,自然就读不到请求了,此时,该客户端下线// 若一直没有读到请求,就在这里阻塞,直到客户端那边发来请求if (!scanner.hasNext()) {// 断开连接了System.out.printf("[%s:%d]:客户端下线\n", clientSocket.getInetAddress(), clientSocket.getPort());break;}// 1. 读取请求并解析String request = scanner.next();// 2. 根据请求计算响应String response = process(request);// 将计算后的响应发送给客户端printWriter.println(response);// flush 起到刷新缓冲区的作用printWriter.flush();// 打印日志System.out.printf("[%s:%d] req:%s res:%s\n", clientSocket.getInetAddress(), clientSocket.getPort(), request, response);}} catch (IOException e) {throw new RuntimeException(e);} finally {try {// 该客户端断开后,就得关闭clientSocket.close();} catch (IOException e) {throw new RuntimeException(e);}}}private String process(String request) {return request;}public static void main(String[] args) throws IOException {TcpEchoServer tcpEchoServer = new TcpEchoServer(9090);tcpEchoServer.start();}
}

        与 UDP 不同的是,TCP协议是 有连接,所以在进行网络通信前,需要客户端和服务器端进行连接,交换彼此的一些信息。

        服务器端的 ServerSocket 通过 accept 方法尝试与客户端 Socket 连接;如果连接成功,则返回一个 Socket对象;没连接到的话,就一直阻塞在这里,直到连接到客户端。

         与 UDP 又不同的是,TCP 是以字节为单位进行读写数据的,故使用 InputStream 和 OutputStream 进行读写数据。

        由于客户端可能不止发送一个请求,所以也是使用死循环,反复尝试读取数据。

        若一直没有读到请求,则会在 hasNext() 这里阻塞,直到客户端发送请求,成功读取到数据。

        写入数据时,必须使用 println,因为这里隐含的表示以 \n 为结束符号结束写入,若没有这一符号,则程序不知道什么时候停止写入。

        在写入时,并不是直接写入到网卡的,而是写入到缓冲区,故在写完时,还需刷新缓冲区,确保数据成功写入到网卡上。

        在客户端断开连接后,需要关闭为客户端创建的 Socket 连接

        对于 TCP协议 来说,需要先处理和客户端发来的连接,通过读写 clientSocket,与客户端进行通信,如果没有客户端发起连接,那么就会阻塞在 accept,这里的阻塞和多线程的阻塞又本质区别

        如果只是一个线程处理连接和读取请求两个工作,由于服务端线程会在 hasNext() 那里阻塞,就不能处理下一个客户端的连接了,所以引入多线程来处理,这里的主线程处理与客户端的连接,连接到一个客户端后,就创建一个线程来处理客户端发送来的请求。

        但是频繁的创建和销毁线程,开销很大,所以引入线程池来处理客户端的请求


TcpEchoClient

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;/*** @author: Themberfue* @date: 2024/11/14 19:37* @description:*/
public class TcpEchoClient {private Socket socket = null;public TcpEchoClient(String serverIp, int port) throws IOException {// TCP 就不需要单独创建额外的变量来保存服务器的ip和端口了// 通过连接会自动保存对端的信息// 直接把字符串的IP的值,设置过来this.socket = new Socket(serverIp, port);}public void start() {Scanner scanner = new Scanner(System.in);try (OutputStream outputStream = socket.getOutputStream();InputStream inputStream = socket.getInputStream()) {// 同样为了使用方便,套壳使用Scanner scannerNet = new Scanner(inputStream);PrintWriter printWriter = new PrintWriter(outputStream);// 客户端可能发送的请求不止一次,所以通过死循环的逻辑(简单的从控制台读取,所以这样)// 该客户端进程结束时,请求就不发了,自然服务端那边就不能读取到了// 这边这个客户端连接就与服务端断开了while (true) {// 从控制台读取客户端的请求String request = scanner.next();// 将客户端的请求发送到服务端// 这个操作只是将数据写入到 "缓冲区",并没有真正写入网卡中printWriter.println(request);// 这里清除缓冲区后,才真正将数据写入到网卡中printWriter.flush();// 读取服务端发送来的请求String response = scannerNet.next();System.out.printf("req:%s res:%s\n", request, response);}} catch (IOException e) {throw new RuntimeException(e);}}public static void main(String[] args) throws IOException {TcpEchoClient tcpEchoClient = new TcpEchoClient("127.0.0.1", 9090);tcpEchoClient.start();}
}

网络编程的知识到这里就差不多结束了~~~

下节我们将进入跟多姿多彩的网络世界里学习~~~ 

毕竟不知后事如何,且听下回分解 

❤️❤️❤️❤️❤️❤️❤️

 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com