java的socket通讯,使用readLine接收还是使用read接收

本文讨论了在网络编程中使用socket接收数据时遇到的问题,特别是当接收的数据最后一行缺少换行符导致循环无法正常跳出的情况。提出了两种解决方案:一种是约定报文前几位表示报文长度,另一种是在报文中约定一个特殊的结束符。同时分析了两种方法的优缺点,并提供了实际应用中的代码示例。

Socket s = new Socket("192.168.218.2", 58100);

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

String info = null;

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

    System.out.println(info);

    }

以上是部分代码,主要是readLine这句,接收字符串的时候,最后一行接收不到,while之后的代码也没有执行,程序处于一个挂起的状态。

上网查了下资料,好像是说最后一行没有回车符,我在服务端加了回车符之后,还是跳不出循环。。。


解决:

readLine只有读取文件等的结尾才会是null

在网络上(都是阻塞模式),readLine是一直等待输入,

即使是对方什么也不输入,只是回车,readLine也不会返回null,所以无法跳出while循环。


在I/O阻塞模式下,你写的条件循环while((line = in.readLine()) != null)是不合理的。

两种方法解决:

(1)双方约定每次发送报文都报文前几个字符表示长度信息,如下

原始报文是:ASDF

发送的socket报文是:0004ASDF

其中0004表示报文长度,接收方先接收四位的长度,再接收余下的报文。


(2)双方约定一个特殊的标志是结束符,比如约定 ==END== 表示结束

代码修改为while(!"==END==".equals(line = in.readLine()))就继续等待接收

这个特殊的结束符需要双方发送报文结束必须再发送的。


第一种解决方法是最常用的。自己接触的几个项目都是此种方式。

附加第一种方法的用法:

byte[] msgHead = new byte[5];// 双方约定前五位表示报文长度

in.read(msgHead, 0, msgHead.length);// 首先读取报文长度信息

String msgLength = new String(msgHead, getEncoding());

int msgLengthInt = Integer.parseInt(msgLength);

byte[] msgBody = new byte[msgLengthInt];// new一个报文长度大小的字节数组

in.read(msgBody, 0, msgBody.length);// 读取报文信息

byte[] recMsg = new byte[msgHead.length + msgBody.length];// 如有需要合并报文长度和报文信息

System.arraycopy(msgHead, 0, recMsg, 0, msgHead.length);

System.arraycopy(msgBody, 0, recMsg, msgHead.length, msgBody.length);


第二种方式,要双方约定一个结束符才能工作,而且存在bug。

对于很多特殊字符或者字节等在传输中转换为String会失真,则双方无法正常通讯。

例如:

byte[] b1 = new byte[10];

for (int i = 0; i < 10; i++) {

b1[i] = (byte) (i - 5);

}

byte[] b2 = new String(b1).getBytes();

for (int i = 0; i < 10; i++) {

System.out.println(b1[i] + " <-> " + b2[i]);

}

输出结果显示byte[]在转换为String在转换为byte[]时候已经失真。

byte[] --> String --> byte[] 发生失真问题参见另一篇文章

http://blog.youkuaiyun.com/fl772333621/article/details/10162447


Java使用Socket进行接收操作主要涉及`ServerSocket`和`Socket`类。`ServerSocket`用于监听指定端口,等待客户端连接;`Socket`用于与客户端建立连接并进行数据的读写操作。 ### 接收数据的方法 在Java中,通过`Socket`的输入流来接收数据,主要步骤如下: 1. 创建`ServerSocket`对象并绑定端口。 2. 调用`ServerSocket`的`accept()`方法等待客户端连接,该方法会返回一个`Socket`对象。 3. 通过`Socket`对象的`getInputStream()`方法获取输入流。 4. 使用输入流的`read()`方法读取数据。 ### 示例代码 以下是一个简单的Java Socket接收数据的示例代码: ```java import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; public class SocketReceiver { public static void main(String[] args) { try { // 创建ServerSocket对象并绑定端口 ServerSocket serverSocket = new ServerSocket(8888); System.out.println("服务器已启动,等待客户端连接..."); // 等待客户端连接 Socket socket = serverSocket.accept(); System.out.println("客户端已连接:" + socket.getInetAddress()); // 获取输入流 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 读取客户端发送的数据 String inputLine; while ((inputLine = in.readLine()) != null) { System.out.println("接收到客户端消息:" + inputLine); } // 关闭资源 in.close(); socket.close(); serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } ``` 上述代码中,首先创建了一个`ServerSocket`对象并绑定到端口8888。然后调用`accept()`方法等待客户端连接,当客户端连接成功后,获取输入流并使用`BufferedReader`逐行读取客户端发送的数据。最后关闭相关资源。 ### 客户端示例代码 为了测试上述服务器代码,以下是一个简单的客户端代码: ```java import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.net.Socket; public class SocketSender { public static void main(String[] args) { try { // 创建Socket对象并连接到服务器 Socket socket = new Socket("localhost", 8888); // 获取输出流 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); // 发送消息 out.write("Hello, Server!"); out.newLine(); out.flush(); // 关闭资源 out.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } } ``` 客户端代码中,创建了一个`Socket`对象并连接到本地的8888端口,然后获取输出流并发送一条消息给服务器。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值