java socketclient 换行_java网络编程之socket(2)

本文介绍了如何使用Java的Socket实现服务端处理多个客户端连接请求,并采用异步方式通信。通过创建新线程处理每个客户端连接,避免同步处理导致的性能问题。同时讲解了使用BufferedReader进行读取时,需注意加入换行符以正确读取数据,以及如何设置Socket的超时时间来防止长时间阻塞。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

异步处理多客户端连接服务端

上篇讲到的是服务端接收一个客户端的请求之后就结束了,不能再接收其他客户端的请求了,实际情况上我们希望服务端能够处理来自不同用户的请求。

想到这里,或许我们可以用一个死循环,在循环体里面ServerSocket调用其accept方法试图接收来自客户端的连接请求。当没有接收到请求的时候,程序会在这里阻塞直到接收到来自客户端的连接请求,之后会跟当前建立好连接的客户端进行通信,完了后会接着执行循环体再次尝试接收新的连接请求。这样我们的ServerSocket就能接收来自所有客户端的连接请求了,并且与它们进行通信了。这就实现了一个简单的一个服务端与多个客户端进行通信的模式。

这样似乎实现了多客户端的请求,但又存在了一个问题:这种服务端处理客户端的连接请求是同步进行的,每次接收到来自客户端的连接请求后,都要先跟当前的客户端通信完之后才能再处理下一个连接请求。这在并发比较多的情况下会严重影响程序的性能,想象下你打开一个网页肯定希望立即得到反馈,而不是一直等着。

因此我们用异步处理与客户端通信的方式。

代码:

public class Server {

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

// 定义一个ServerSocket监听在端口8888上

int port = 8888;

int i = 1; // 连接计数

// server尝试接收其他Socket的连接请求,

ServerSocket server = new ServerSocket(port);

while (true) {

// server的accept方法是阻塞式的 ,即等待着客户端的请求

Socket socket = server.accept();

// 每接收到一个Socket就建立一个新的线程来处理它

new Thread (new Link(socket)).start();

System.out.println("连接" + i++);

}

}

/**

* 处理客户端Socket连接请求

*/

static class Link implements Runnable {

private Socket socket;

public Link(Socket socket) {

this.socket = socket;

}

public void run() {

try {

handleSocket();

} catch (Exception e) {

e.printStackTrace();

}

}

//跟客户端Socket进行通信

private void handleSocket() throws Exception {

// 跟客户端建立好连接,我们就可以获取socket的InputStream,从中读取客户端发过来的信息。

Reader reader = new InputStreamReader(socket.getInputStream());

char chars[] = new char[64];

int len;

StringBuilder sb = new StringBuilder();

String temp;

int index;

while ((len = reader.read(chars)) != -1) {

temp = new String(chars, 0, len);

if ((index = temp.indexOf("eof")) != -1) { // 遇到eof时就结束接收

sb.append(temp.substring(0, index));

break;

}

sb.append(temp);

}

System.out.println("from client: " + sb);

// 读完后写数据

Writer writer = new OutputStreamWriter(socket.getOutputStream());

writer.write("Hello Client:我是服务端输入数据");

// 释放资源

writer.flush();

writer.close();

reader.close();

socket.close();

}

}

}

输出

e7250d97aa74ceb136bddcc7b9c4e4ea.png

上述代码中,每次ServerSocket接收到一个新的Socket连接请求后都会新起一个线程来跟当前Socket进行通信,这样就达到了异步处理与客户端Socket进行通信的情况。

BurfferReader读取

对哦,还有一点,Socket的InputStream中接收数据时,一个一个字符的读有点太复杂了,有时候我们就会换成使用BufferedReader来一次读一行。

读取数据时用BufferedReader的readLine 方法

BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));

char chars[] = new char[64];

int len;

StringBuilder sb = new StringBuilder();

String temp;

int index;

while ((temp=br.readLine()) != null) {

System.out.println(temp);

if ((index = temp.indexOf("eof")) != -1) {//遇到eof时就结束接收

sb.append(temp.substring(0, index));

break;

}

sb.append(temp);

}

需要注意的是,BufferedReader的readLine方法是一次读一行的,这个方法是阻塞的,直到它读到了一行数据为止程序才会继续往下执行,即直到程序遇到了换行符或者是对应流的结束符readLine方法才会认为读到了一行,才会结束其阻塞,让程序继续往下执行。

所以我们在使用BufferedReader的readLine读取数据的时候一定要记得在对应的输出流里面一定要写入换行符(流结束之后会自动标记为结束,readLine可以识别),写入换行符之后一定记得如果输出流不是马上关闭的情况下记得flush一下,这样数据才会真正的从缓冲区里面写入。

即在输入数据后记得在加入换行符,例

writer.write("Hello ,我是客户端输入数据1111");

writer.write("eof\n"); `

如果客户端中读取来自服务端数据也用bufferedReader的readLine时,记得也要在服务端write写入数据后添加换行符。

设置时间超时

这个应该我们都遇到过,客户端需要通过Socket从服务端获取到信息,然后给用户展示在页面上。Socket在读数据的时候是阻塞式的,如果没有读到数据程序会一直阻塞在那里。在同步请求的时候我们肯定是不能允许这样的情况发生的,这就需要我们在请求达到一定的时间后控制阻塞的中断,让程序得以继续运行。Socket为我们提供了一个setSoTimeout()方法来设置接收数据的超时时间,单位是毫秒。当设置的超时时间大于0,并且超过了这一时间Socket还没有接收到返回的数据的话,Socket就会抛出一个SocketTimeoutException。

例:设置6秒超时

client.setSoTimeout(6000);

try{

while ((len=reader.read(chars)) != -1) {

temp = new String(chars, 0, len);

if ((index = temp.indexOf("eof")) != -1) {

sb.append(temp.substring(0, index));

break;

}

sb.append(new String(chars, 0, len));

}

} catch (SocketTimeoutException e) {

System.out.println("数据读取超时。");

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值