帮助文档
专业提供香港服务器、香港云服务器、香港高防服务器租用、香港云主机、台湾服务器、美国服务器、美国云服务器vps租用、韩国高防服务器租用、新加坡服务器、日本服务器租用 一站式全球网络解决方案提供商!专业运营维护IDC数据中心,提供高质量的服务器托管,服务器机房租用,服务器机柜租用,IDC机房机柜租用等服务,稳定、安全、高性能的云端计算服务,实时满足您的多样性业务需求。 香港大带宽稳定可靠,高级工程师提供基于服务器硬件、操作系统、网络、应用环境、安全的免费技术支持。
服务器资讯 / 香港服务器租用 / 香港VPS租用 / 香港云服务器 / 美国服务器租用 / 台湾服务器租用 / 日本服务器租用 / 官方公告 / 帮助文档
【网络编程】——基于TCP协议实现回显服务器及客户端
发布时间:2024-02-27 19:13:51   分类:帮助文档
【网络编程】——基于TCP协议实现回显服务器及客户端





个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【网络编程】【Java系列】 本专栏旨在分享学习网络编程的一点学习心得,欢迎大家在评论区交流讨论💌



目录
一、TCP实现回显服务器二、服务器端三、客户端四、运行结果


一、TCP实现回显服务器
TCP提供的API主要有两个类Socket(既会给服务器使用也会给客户端使用)和ServerSocket(一般为服务器使用)。TCP将数据分割成以字节为单位的小数据块进行传输(一个TCP数据报就是一个字节数组byte[])。
二、服务器端

在服务器端创建一个ServerSocket对象,并绑定一个端口号。


进入while循环: 注意这里和Udp实现回显服务器不同的是,Tcp进入循环之后并不是读取客户端请求,而是先处理客户端的连接(Tcp是一个有连接的协议(Udp是没有连接的协议),所以有连接的话会优先处理连接,连接可以理解为客户端和服务器彼此之间保留对方的信息)。一个服务器要应对很多客户端,在服务器内核中有很多客户端的连接,在应用程序层面我们需要对这些连接进行一一处理,这里服务器内核中的连接就像一个一个的待办事项一样,这些待办事项在队列这样的数据结构中,所以应用程序需要一一完成这样的任务(这个过程类似于生产者消费者模型)。 serverSocket.accept()方法可以将服务器内核中的连接获取到应用程序中
当程序启动之后就会立刻执行到accept方法,在调用serverSocket.accept()方法之后,如果此时没有客户端连接请求到达,该方法会一直阻塞,直到有客户端与服务器成功建立连接才会继续执行。 现在来解释这里的返回值问题,serverSocket.accept()方法会返回一个Socket对象:我们已经直到accept方法会把服务器内核已经建立好的连接拿到应用程序中,但是accpet方法的返回值并非是一个Connection这样的对象,而是Socket这样的对象。 这里返回的Socket对象相当于一个耳麦,既可以发出自己的声音也可以听到对方的声音(我们不需要管对方是谁,我们只需要对着这个耳麦说话就行)。然后我们通过Socket对象与对方进行网络通信


Socket和ServerSocket: ServerSocket类用于在服务器端创建一个服务器套接字,它监听指定的端口,等待客户端的连接请求:通过调用ServerSocket的accept()方法,服务器监听指定端口,直到有客户端发起连接请求,accept()方法才返回一个表示客户端连接的Socket对象。通过这个Socket对象,可以进行与客户端的通信。 Socket类用于创建一个客户端套接字,它是客户端与服务器进行通信的终点:通过调用Socket的构造方法,指定服务器的主机名和端口号,可以与服务器建立连接。 总的来说:ServerSocket用于监听端口,接受客户端的连接请求并返回一个Socket对象,而Socket用于与服务器建立连接,并进行数据的读写操作。通过这两个类的配合,实现了TCP协议下的客户端与服务器之间的通信。

服务器端代码如下
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TcpEchoServer {
private ServerSocket serverSocket = null;
private ExecutorService service = Executors.newCachedThreadPool();
// 绑定端口号
public TcpEchoServer(int port) throws IOException {
serverSocket = new ServerSocket(port);
}

// 启动服务器
public void start() throws IOException {
System.out.println("服务器启动!!!");
while(true) {
// 注意这里和Udp不同的是,Tcp进入循环之后并不是读取客户端请求,而是先处理客户端的连接
// Tcp是一个有连接的协议(Udp是没有连接的协议),所以有连接的话会优先处理连接
// 连接可以理解为客户端和服务器彼此之间保留对方的信息
// 一个服务器要应对很多客户端,在服务器内核中有很多客户端的连接,在应用程序层面我们需要对这些连接进行一一处理
// 这里服务器内核中的连接就像一个一个的待办事项一样,这些待办事项在队列这样的数据结构中
// 所以应用程序需要一一完成这样的任务
Socket clientSocket = serverSocket.accept();
// Thread t = new Thread(() -> {
// processConnection(clientSocket);
// });
// t.start();
service.submit(new Runnable() {
@Override
public void run() {
processConnection(clientSocket);
}
});
}
}

// 通过这个方法来处理连接的逻辑
private void processConnection(Socket clientSocket) {
System.out.printf("[%s:%d] 客户端上线啦!!!\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
// 接下来读取请求,根据请求计算响应,最后再返回响应
// Socket对象内部包含了两个字节流对象,我们需要先获取到这个字节流对象,然后再完成后续的读写操作
try (InputStream inputStream = clientSocket.getInputStream();
OutputStream outputStream = clientSocket.getOutputStream()) {
// 一次连接中可以涉及到多次请求和响应
while( true ) {
// 第一步:读取请求并进行解析
// 这里为了读取方便,我们直接使用Scanner
Scanner scanner = new Scanner(inputStream);
if(!scanner.hasNext()) {
// 读取完毕客户端下线

System.out.printf("[%s:%d] 客户端下线!!!\n]",clientSocket.getInetAddress().toString(),clientSocket.getPort());
break;
}
// 这里我们约定客户端输入来的请求是文本数据,同时以空白符作为分割
String request = scanner.next();

// 第二步:根据请求计算响应
String response = process(request);

// 第三步:把响应写回给客户端,把OutputStream使用PrinterWriter进行包装,方法进行数据的传输
PrintWriter writer = new PrintWriter(outputStream);
writer.println(response);

// 刷新缓冲区
writer.flush();

// 打印当前的请求详情
System.out.printf("[%s:%d] req: %s, resp: %s\n",clientSocket.getInetAddress().toString(),
clientSocket.getPort(),request,response);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
clientSocket.close();
} catch (IOException e) {
// 这里必须确保Socket能够被关闭
e.printStackTrace();
}
}
}

private String process(String request) {
return request;
}

public static void main(String[] args) throws IOException {
TcpEchoServer server = new TcpEchoServer(9090);
server.start();
}
}

三、客户端
关于回显服务器这里我们来看客户端的代码是如何进行编写的,主要有4个步骤,如下:
第一步:从控制台上读取用户的输入。第二部:把输入的内容构造成请求,并将其发送给服务器。第三步:从服务器读取响应最后一步:把响应显示到控制台上。
客户端代码如下:
import java.io.*;
import java.net.Socket;
import java.util.Scanner;

public class TcpEchoClient {
private Socket socket = null;

// 要和服务器进行通信的话我们就需要先知道服务器的位置外哪里。
public TcpEchoClient(String serverIp,int serverPort) throws IOException {
socket = new Socket(serverIp,serverPort);
}

public void start() {
System.out.println("客户端启动!!!");
Scanner scannerConsole = new Scanner(System.in);
try(InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream()) {
while(true) {
// 从控制台输入一个字符串
System.out.print("-> ");
String request = scannerConsole.next();
// 把请求发送给服务器
PrintWriter printWriter = new PrintWriter(outputStream);
// 使用println加上换行,后续服务器读取请求的时候就可以使用scanner.next来获取了
printWriter.println(request);
// 调用flush确保数据发送出去了
printWriter.flush();
// 从服务器中读取响应
Scanner scannerNetwort = new Scanner(inputStream);
String response = scannerNetwort.next();
// 把响应打印出来
System.out.println(response);
}
} catch (IOException e) {
e.printStackTrace();
}

}
public static void main(String[] args) throws IOException {
TcpEchoClient client = new TcpEchoClient("127.0.0.1",9090);
client.start();
}
}

四、运行结果

运行结果如下:

本文到这里就结束了,希望友友们可以支持一下一键三连哈。嗯,就到这里吧,再见啦!!!




香港云服务器租用推荐
服务器租用资讯
·广东云服务有限公司怎么样
·广东云服务器怎么样
·广东锐讯网络有限公司怎么样
·广东佛山的蜗牛怎么那么大
·广东单位电话主机号怎么填写
·管家婆 花生壳怎么用
·官网域名过期要怎么办
·官网邮箱一般怎么命名
·官网网站被篡改怎么办
服务器租用推荐
·美国服务器租用
·台湾服务器租用
·香港云服务器租用
·香港裸金属服务器
·香港高防服务器租用
·香港服务器租用特价