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

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

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

}

写在最后

很多人感叹“学习无用”,实际上之所以产生无用论,是因为自己想要的与自己所学的匹配不上,这也就意味着自己学得远远不够。无论是学习还是工作,都应该有主动性,所以如果拥有大厂梦,那么就要自己努力去实现它。

最后祝愿各位身体健康,顺利拿到心仪的offer!

由于文章的篇幅有限,所以这次的蚂蚁金服和京东面试题答案整理在了PDF文档里

蚂蚁、京东Java岗4面:原理+索引+底层+分布式+优化等,已拿offer

蚂蚁、京东Java岗4面:原理+索引+底层+分布式+优化等,已拿offer

蚂蚁、京东Java岗4面:原理+索引+底层+分布式+优化等,已拿offer
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!
无用论,是因为自己想要的与自己所学的匹配不上,这也就意味着自己学得远远不够。无论是学习还是工作,都应该有主动性,所以如果拥有大厂梦,那么就要自己努力去实现它。

最后祝愿各位身体健康,顺利拿到心仪的offer!

由于文章的篇幅有限,所以这次的蚂蚁金服和京东面试题答案整理在了PDF文档里

[外链图片转存中…(img-VVMhdsEV-1714674828199)]

[外链图片转存中…(img-RBgZONXD-1714674828199)]

[外链图片转存中…(img-QzYTFaYM-1714674828200)]
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

  • 15
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值