JavaWeb~实现简单的TCP网络服务器与客户端 并使用线程池解决多连接问题

ServerSocket(int port) 创建绑定到指定端口的服务器套接字

ServerSocket(int port, int backlog) 创建服务器套接字并将其绑定到指定的本地端口号,并指定了积压。

Socket accept() 侦听要连接到此套接字并接受它

bind(SocketAddress endpoint) 将ServerSocket绑定到特定地址(IP地址和端口号)

InetAddress getInetAddress() 返回此服务器套接字的本地地址

void close() 关闭此套接字

int getLocalPort() 返回此套接字正在侦听的端口号

  • 重要方法 accept()
  1. 三次握手完成后, 服务器调用accept()接受连接;

  2. 如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来;

  3. Socket 是其返回值,代表网络的套接字

Socket类


Socket(InetAddress address, int port) 创建流套接字并将其连接到指定IP地址的指定端口号

Socket(String host, int port) 创建流套接字并将其连接到指定主机上的指定端口号

void bind(SocketAddress bindpoint) 将套接字绑定到本地地址

void connect(SocketAddress endpoint) 将此套接字连接到服务器

InetAddress getInetAddress() 返回套接字所连接的地址

InputStream getInputStream() 返回此套接字的输入流

OutputStream getOutputStream() 返回此套接字的输出流

简单的TCP服务器与客户端

============================================================================

  • 服务器

import java.io.*;

import java.net.ServerSocket;

import java.net.Socket;

public class TcpEchoServer {

// 1. 初始化服务器

// 2. 进入主循环

// 1) 先去从内核中获取到一个 TCP 的连接

// 2) 处理这个 TCP 的连接

// a) 读取请求并解析

// b) 根据请求计算响应

// c) 把响应写回给客户端

private ServerSocket serverSocket = null;

public TcpEchoServer(int port) throws IOException {

// 这个操作和前面的 UDP 类似, 也是要绑定端口号.

serverSocket = new ServerSocket(port);

}

public void start() throws IOException {

System.out.println(“服务器启动”);

while (true) {

// 1) 先从内核中获取到一个 TCP 连接

Socket clientSocket = serverSocket.accept();

// 2) 处理这个连接

processConnection(clientSocket);

}

}

private void processConnection(Socket clientSocket) {

System.out.printf(“[%s:%d] 客户端上线\n”, clientSocket.getInetAddress().toString(),

clientSocket.getPort());

// 通过 clientSocket 来和客户端交互, 先做好准备工作. 获取到 clientSocket 中的流对象

try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()))) {

// 此处咱们先实现一个 “长连接” 版本的服务器.

// 一次连接的处理过程中, 需要处理多个请求和响应.

// 这个循环何时结束? 当客户端断开连接时, 就结束了.

// 当客户端断开连接的时候, 服务器再去调用 readLine 或者 write 方法都会触发异常 (IOException)

while (true) {

// 1. 读取请求并解析(此处的 readLine 对应客户端发送数据的格式, 必须是按行发送)

String request = bufferedReader.readLine();

// 2. 根据请求计算响应

String response = process(request);

// 3. 把响应写回到客户端(客户端要按行来读)

bufferedWriter.write(response + “\n”);

//因为使用的是带缓冲区的buffer 所以一开始write是写入了缓冲区里 调用flush才可以将数据真正写到socket文件中

bufferedWriter.flush();

System.out.printf(“[%s:%d] req: %s; resp: %s\n”, clientSocket.getInetAddress().toString(),

clientSocket.getPort(), request, response);

}

} catch (IOException e) {

// e.printStackTrace();

System.out.printf(“[%s:%d] 客户端下线\n”, clientSocket.getInetAddress().toString(),

clientSocket.getPort());

}

}

public String process(String request) {

return request;

}

public static void main(String[] args) throws IOException {

TcpEchoServer server = new TcpEchoServer(9090);

server.start();

}

}

  • 客户端

import java.io.*;

import java.net.Socket;

import java.util.Scanner;

public class TcpEchoClient {

// 1. 启动客户端(一定不要绑定端口号) 和服务器建立连接

// 2. 进入主循环

// a) 读取用户输入内容

// b) 构造一个请求发送给服务器

// c) 读取服务器的响应数据

// d) 把响应数据显示到界面上.

private Socket socket = null;

public TcpEchoClient(String serverIp, int serverPort) throws IOException {

// 此处的实例化 Socket 过程, 就是在建立 TCP 连接

socket = new Socket(serverIp, serverPort);

}

public void start() {

System.out.println(“客户端启动”);

Scanner scanner = new Scanner(System.in);

try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))) {

while (true) {

// 1. 读取用户输入内容

System.out.print(“->”);

String request = scanner.nextLine();

if (“exit”.equals(request)) {

break;

}

// 2. 构造请求并发送. 此处 + \n 为了和服务器中的 readLine 相对应.

bufferedWriter.write(request + “\n”);

//因为使用的是带缓冲区的buffer 所以一开始write是写入了缓冲区里 调用flush才可以将数据真正写到socket文件中

bufferedWriter.flush();

// 3. 读取响应数据.

String response = bufferedReader.readLine();

// 4. 把响应数据显示到界面上.

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();

}

}

线程池版本的TCP服务器

===========================================================================

  • 观察运行上述代码我们发现再启动一个客户端, 尝试连接服务器, 发现第二个客户端, 不能正确的和服务器进行通信.分析原因, 是因为我们accecpt了一个请求之后, 就在一直while循环尝试read, 没有继续调用到accecpt, 导致不能接受新的请求.我们当前的这个TCP, 只能处理一个连接, 这是不科学的

  • 所以我们通过每个请求, 创建子进程的方式来支持多连接

  • 但是还有问题当我们有很多连接的时候 线程就会疯狂的创建和销毁 所以结合前面所学我们可以使用线程池进行优化

import java.io.*;

import java.net.ServerSocket;

import java.net.Socket;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class TCPThreadPoolServer {

//去内核找连接

//处理这个连接对象

//获得socket的输入流

//处理输入流请求

//将响应写回到socket输出流

private ServerSocket serverSocket = null;

//构造函数需要给服务器绑定一个端口

public TCPThreadPoolServer(int port) throws IOException {

this.serverSocket = new ServerSocket(port);

}

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
a-1715352920725)]

[外链图片转存中…(img-mvmNvBE8-1715352920726)]

[外链图片转存中…(img-7qAHqJ6b-1715352920726)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 27
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值