`
QING____
  • 浏览: 2233757 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

JAVA Socket与Bufferd IO

    博客分类:
  • JAVA
 
阅读更多

    今天开发一个Socket通讯agent,Java 程序中启动一个ServerSocket,用来与shell脚本中"nc"命令通讯并交换数据.ServerSocket可以收到"nc"发送的数据,但是"nc"却接受不到数据..代码样例:

try {
		InputStreamReader reader = new InputStreamReader(innerSocket.getInputStream());
		StringBuffer sb = new StringBuffer();
		while (true) {
			int _c = reader.read();
			if (_c == -1) {
				break;
			}
			sb.append((char) _c);
		}
		String data = StringUtils.trim(sb.toString());
		//如果数据异常
		if (StringUtils.isBlank(data)) {
			return;
		}
		BufferedWriter out = new BufferedWriter(new OutputStreamWriter(innerSocket.getOutputStream()));
		out.write(">>>" + data);
		out.newLine();
		//out.flush();//++++important
		}
	} catch (Exception e) {
		log.error(e);
	}finally {
		try{
			innerSocket.close();
		}catch (Exception e){
			//
		}
	}
}

   shell调用方式:

>echo ping | nc 127.0.0.1 10101

    代码非常简单, 可是为什么不行呢?通过跟踪,Java代码中可以从socket中read到"ping"字符串,但是为什么out.write(">>>")的数据不能被shell获取呢??OK,换一下代码风格,再试一试:

 

OutputStream out = innerSocket.getOutputStream();
String back = ">>>" + data;
out.write(back.getBytes());
...

    不好意思,成功了...为什么BufferedWriter不行,反而OutStream行呢?后来简单的翻阅了一下源码,简单的修改一下即可:

 

BufferedWriter out = new BufferedWriter(new OutputStreamWriter(innerSocket.getOutputStream()));
out.write(">>>" + data);
out.newLine();
out.flush();

加上"out.flush()"即可,对于BufferedWriter而言,write()方法并没有直接将数据写入到物理的IO流中,而是首先cache在了一个字节数组中,只有当cache的数据量达到buffer-size时才会触发flush,flush的作用就是将多个字节依次写入到IO中,原以为socket.close()方法会执行flush(),尽管OutputStream中有flush方法,事实上没有执行.

 

  • public BufferedWriter(Writer out, int bufferSize)

所以使用BufferedWriter的时候,一定要在IO关闭之前,调用flush()方法,否则将会丢失部分数据...真是费劲.

 

    不过顺便还要提一个问题,如果JAVA Socket向远端write数据后,却始终收不到远端发来的数据,还可能有下面的一种情况:

 

BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write("success 1123");
writer.flush();
//socket.shutdownOutput();
InputStreamReader reader = new InputStreamReader(socket.getInputStream());
StringBuffer sb = new StringBuffer();
while(true){
	int _c = reader.read();
	if(_c == -1){
		break;
	}
	sb.append((char)_c);
}
System.out.println(">>>>read:" + sb.toString());
socket.close();

    上面的代码中,socket向远端write数据之后,开始read远端返回的数据,但是始终无法read到数据,是怎么回事?其实原因也很简单,这就是典型的"Socket死锁": socket write()时,同时远端也在read,因为socket通讯是基于流(frame)的,如果远端read时没有收到EOF,那么read操作将一直阻塞,直到socket关闭.上面的代码,就是出现了远端socket read一直阻塞而没有机会执行write,同时本地socket也因为read阻塞,导致了"死锁",代码调整如下:

 

BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write("success 1123");
writer.flush();
socket.shutdownOutput();
...

    在writer数据结束后,执行shutdownOutput,将output流通道关闭,此时远端socket就会read到EOF, 认为通道中不会再有数据可读.shutdownOutput()方法不会关闭整个socket,只是关闭了socket中的outputStream,不过一旦调用了此方法,此后将不能再调用writer.write()方法.

    此外还可以通过socket IO字节成帧手段来解决上述问题.

分享到:
评论

相关推荐

    字符缓冲流Bufferd

    字符缓冲流Bufferd,直接粘贴到eclipse或者cmd运行即可

    CCNP培训资料(CISCO认证)

    logging bufferd terminal monitor passive interface banner motd show log logging buffered no logging console show frame-relay lmi interface s0.2 point-to-point show IPX interface it takes place through...

    goredis:golang redis 客户端,缓冲连接,连接池

    goredisgolang redis client, bufferd connection, connection pool, support all redis commands,欢迎大家批评指正,更欢迎大家加入进来。Create a new conn? c, e := Dial("127.0.0.1:6379", pwd, CTimeout, ...

    cFE:核心飞行系统(cFS)核心飞行执行器(cFE)

    核心飞行系统:框架:核心飞行执行器 该存储库包含NASA的Core Flight Executive(cFE),它是Core Flight System的框架组件。 这是服务和相关框架的集合... 重构SB缓冲区描述符对象CFE_SB_BufferD_t并简化零复制缓冲区

    麦肯锡-年月―中国xx集团战略咨询项目建议书.ppt

    麦肯锡-年月―中国xx集团战略咨询项目建议书.ppt

    廖倩5.14运营款.xlsx

    廖倩5.14运营款.xlsx

    setuptools-25.0.2-py2.py3-none-any.whl

    文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    全网第一个宝宝生活记录网站root ca

    全网第一个宝宝生活记录网站,帮我写一个网站介绍,网址 https://43.136.21.175/ ,二维码分享和登录,统计记录最近时间,功能很全很实用,手机和电脑都可以访问,手机浏览器可以生成快捷方式到桌面和App一样,点右上角可以打开菜单,里面我做了图表统计可以看每天的喂养次数哪些,我们一直在用,很方便的

    yes I can.mp3

    yes I can.mp3

    IMG20240426155740.jpg

    IMG20240426155740.jpg

    4-8.py

    4-8

    基于python的舞蹈视频推荐系统相关实验设计与实现

    【作品名称】:基于python的舞蹈视频推荐系统相关实验设计与实现 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【项目介绍】:主要分为三个实验阶段,数据构建以及处理;召回阶段;排序阶段 数据构建 ####开发环境为:Windows10 + python3.8 本教程主要是针对B站舞蹈视频进行数据获取,数据来源于B站舞蹈区的中国舞和舞蹈教程两个板块,获取的视频日期为2021.08.01-2.21.12.31。主要分为五部分数据获取,每部分具体获取内容如下: 舞蹈信息表,这部分按月份进行获取,由于舞蹈教程较少,因此月份合并获取。最后将所有获取的数据整合成一张表。 舞蹈_用户交互表,这部分根据舞蹈信息表获取的视频url,获取评论区用户ID以及相关链接,并将label值设为1;为提高获取速度,将源表进行拆分,分为多张表在不同的代码以及IP环境中运行。 用户信息表,首先根据交互表的user_id获取user_id的集合,然后根据user_id获取用户的公开信息。 舞蹈封面,根据舞蹈信息表的pic的url获取封

    matlab机器人课程和书籍中的问题.zip

    matlab机器人课程和书籍中的问题.zip

    基于yolov8+pyqt5实现精美界面支持图片视频和摄像检测源码.zip

    基于yolov8+pyqt5实现精美界面支持图片视频和摄像检测源码.zip

    2-9.py

    2-9

    zigbee 简单控制LED灯状态

    zigbee 简单控制LED灯状态

    pytest-7.1.2-py3-none-any.whl

    文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    独立按键控制数码管显示0-F.zip

    独立按键控制数码管显示0-F.zip

    Scrapy-2.7.0.tar.gz

    文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

Global site tag (gtag.js) - Google Analytics