Socket服务端和客户端阻塞问题

在学习Socket编程时,遇到客户端发送数据后被阻塞的问题。分析发现,服务端读取数据时无法判断何时结束,导致双方阻塞。解决方案包括:数据传输时确保刷新流,或在传输结束后调用socket.shutdownOutput()和socket.shutdownInput()来关闭流,通知对方结束信号。

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

  这两天没事学习的时候,看到了一个boi的一个例子,自己按照教程编写的时候,发现怎么运行都不成功,客户端一直被阻塞在读的地方,debug也没有查到问题的关键,后来找了很多地方,也没有看到太好的解释。后来就看api发现了两个方法,测试了一下,发现好用了。

  简要介绍一下案例

我的客户端发送一个时间给服务端,然后服务端接收这个数据并给客户端返回一个数据,然后客户端接收这个数据并输出。


我在实现这个功能的时候,发现客户端和服务端启动后都被阻塞住了,原因是当客户端给服务端发送完数据的时候服务端在读取数据,但是服务端没有办法判断什么时候会自动中断,所以他会在这个地方阻塞。阻塞之后服务端就没有办法往客户端发送数据,这个时候客户端的接收数据也会等服务端的数据,会在这里阻塞。这个时候服务端和客户端都不会关闭,会一直持续阻塞。

造成这个问题一共有两个原因,

第一传递数据的时候,另一端不知道什么时候终止,用read!=-1是没有办法判断出来的,因为流没有终止,流一直存在,所以另一端以为数据没有传输完毕

第二,如果数据量不够大的话,就会造成数据被写入内存,而没有被传输过去,只是被放到了内存。

解决这两个问题,第一个在你传输的时候随时记得刷新一下flush()或者使用一些会自动刷新的写的方法如println();第二个问题就是,在传输结束之后,你可以把流进行关闭,使用socket.shutdownOutput()socket.shutdownInput()这两个方法,将流关闭掉,对面就可以接收到结束的信号。

我的代码如下你们可以用我这个代码进行测试,关键地方我可以删除那几条测试看看有什么反应。

server端

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * server运行
 * @author pg
 */
public class TimeService {
	
	public static void main(String[] args) {
		int port = 12345;
		ServerSocket server = null;
		try {
			server = new ServerSocket(port);
			
			while(true){
				Socket accept = server.accept();
				
				new Thread(new RunableTimeService(accept)).start();;
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			if(server!=null){
				try {
					server.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
	}
}

服务端线程的实现方法

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Date;
public class RunableTimeService implements Runnable {
	private Socket socket;
	public RunableTimeService(Socket accept) {
		socket = accept;
	}

	@Override
	public void run() {
		
		BufferedReader in = null;
		PrintWriter out = null;
		try {
			in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
			out = new PrintWriter(socket.getOutputStream(),true);
			String body = null;
			while(true){body = in.readLine();
				if(body==null)
					break;
				System.out.println("in  "+body);
			}
			//关闭输入的流
			socket.shutdownInput();
			
			//使用println输出,带有自动刷新的功能
			out.println("server out put "+new Date().getTime());
			//关闭输出的流
			socket.shutdownOutput();
			
			socket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			if(in!=null){
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(out!=null){
				try {
					out.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			if(socket!=null){
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
		}
	}

}


client端

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Date;
/**
 * client运行
 * @author pg
 *
 */
public class TimeClient {
	public static void main(String[] args) {
		Socket socket = null;
		BufferedReader in = null;
		PrintWriter out = null;
		try {
			socket = new Socket("127.0.0.1", 12345);
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			out = new PrintWriter(socket.getOutputStream(),true);
			//输出一个时间 
			out.write("client  "+new Date().getTime());
			//刷新输出的数据
			out.flush();
			//关闭输出的流
			socket.shutdownOutput();
			
			while(true){
				
				String body = in.readLine();
				if(body==null)
					break;
				System.out.println("server time is + "+body);
			}
			//关闭输入的流
			socket.shutdownInput();
			
		}catch (IOException e) {
			e.printStackTrace();
		}finally {
			if(in!=null){
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(out!=null){
				try {
					out.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			if(socket!=null){
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

如有问题 谢谢更正

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值