`

Java Socket 01 - 常识篇之消息处理

阅读更多

 

最近的工作也不是很忙,所以有时间来总结一下Socket一些基本的东西,希望对新学的朋友起到积极的作用。写作的能力不行,本来有很多东西想写,但是到了写的时候就想不起来了。最后会附上一个例子,例子简单模拟了心跳机制。
   这里我还是那一句:多去官网,那里有你想要的东西
http://docs.oracle.com/javase/tutorial/networking/sockets/definition.html
在这里不会过多地说关于网络方面的基础,如果有兴趣的朋友,可以看看O’REILLY的《Java网络编程》。
 其实两台机器之间的通信有点像两个人的谈话。先来看看下面的一段平时的对话,平时我和女同事间的对话,我们就根据下面一段话来展开本篇文章:
 Kitty :Jimmy,早啊
Jimmy:Kitty,早啊
Kitty :周末去东莞爽了吗
Jimmy:哈哈。爽啊。被各种服务了
……..
Jimmy :拜
Kitty : 拜
走了几步….
Lili : Hi, Jimmy
Jimmy : Hi ,Lili
Lili : 听说你周末很爽哦。
Jimmy : 一般般啦

Jimmy : 拜
Lili:拜
下面由我来解释这段话的意义。当Kitty,喊出Jimmy的时候,这时我抬起头看着她,因为Jimmy是我的名字,这时我们已经“建立了连接” ,当Kitty说出‘早啊’的时候,我知道她用的是母语中文,出于礼貌我就会马上回复一句中文‘早啊’,因为我知道别人向你问好,你也不能太没礼貌,这样Kitty就完成“发送数据”,而我完成了“接收数据” 并且做出了响应,我和她“交互”了一会后,彼此说了“拜”,然后我们就“关闭了连接”。接着Lili上来搭讪,这时我就像一台服务器,为各位美女提供了各种服务器,回答这个那个问题。。。
(一) 、何为Socket 套接字?
学过网络的同学都知道,两台计算机实现通信,是一个复杂的过程,其中包括数据包、纠错、包重传等等,幸运的是,这些都不需要自己来实现,Socket可以让我们将网络连接视为一种可以读取字节的流,Socket掩盖了网络的底层细节。说白了,Socket就是两台主机之间的一个连接,但是对于写程序的来说,它也许就是一个顶层的API,通过这个API,我们在两台终端间进行通信。如下图(来自google):


      上面的图中,描述了一个主机中,应用程序、套接字、协议、端口号之间的逻辑关系。不同类型的套接字与不同类型的底层协议族以及协议族中的不同协议栈相关联,本篇文章只是基于TCP/IP协议的Socket。在Java中,为TCP/IP协议族提供了两个类:Socket和ServerSocket。一个Socket实例代表了TCP连接的一端,简单地说就是一台电脑中的一个应用程序。
客户端Socket有哪些的基本操作:
1) 连接远程机器
2) 发送数据
3) 接收数据
4) 关闭连接
5) 绑定端口
6) 监听入站数据
7) 在所绑定端口上接受来自远程机器的连接。
服务器端ServerSocket:
1) 创建一个新的ServerSocket
2) 使用accept()在指定端口监听入站的连接。accept()会一直阻塞,知道有客户端尝试连接。
3) 根据服务器类型,获取客户端的输出、输入流。
4) 服务器与客户端根据协议交互,直到关闭连接
5) 服务器返回步骤2),等待下一次连接
(二)、消息的发送和接收
从开头的那段对话,我们可以总结出 :
建立连接   消息进行编码   发送消息   接收消息   消息解码  关闭连接 。
看到这里也许你会有疑问,也许你会问人类谈话是“智能”的,我们谈话中,自己能准确判断另外一个人怎样才算说完一句话,并且能做出回答,而套接字间怎么来完成呢?机器是没有那么智能,它不能判断对方什么时候把一句话说完,这些都要我们为机器协商好,比如, 1)当接收到“/n”就说明一句话已经完成。
2)把整句话的长度告诉另外一方。
说到这里,就引入两个概念:
基于定界符(Delimiter-based):消息的结束有由一个唯一的标记指出,即发送者在传输完成后显式添加一个特殊字节序列,这个特殊标记不能在传输的数据中出现。这种方式,这里就不多说了,大家可以去Google一下。
显式长度(Explicit length):在变长字段或消息前附加一个固定大小的字段,用来指示该字段或消息中包含了多少字节。现在大多Socket应用都是采取这种方式。最后的例子也是采取这种方式。
下面的一段核心代码是显式长度(Explicit length)的一种实现:发送消息前先把消息的长度告知对方 (如果对ByteBuffer不明白的,请看前面发表的两篇文章NIO 01 、NIO02)
发送端:

public void setMsg(String sMsg){
		try {
			if(m_handler.socket().isClosed()){ 
				JOptionPane.showMessageDialog(null, "Please reconnect");
				return ;
			}
			int iLen = sMsg.getBytes("utf-8").length;
			// 发送消息的长度
			m_handler.out().write(BasicTypeConverter.intToByte(iLen));
			// 发送消息
			m_handler.out().write(sMsg.getBytes("utf-8"), 0 , iLen);
			m_handler.out().flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

 

 

接收端:

			// message head info 
			byte[] bHead = new byte[4];
			while(true){
				if(m_oIn.read(bHead) == -1){
					break;
				}
				// 获取到消息的长度
				int iSize = BasicTypeConverter.bytesToInt(bHead);
				// 输入流中可读的长度
				int iAvailable = m_oIn.available();
				ByteBuffer bBuffer = ByteBuffer.allocate(iSize);
				if(iSize > iAvailable){
				// 直到消息接收完成
					while(bBuffer.hasRemaining()){
						byte[] bb = new byte[iAvailable];
						m_oIn.read(bb);
						bBuffer.put(bb);
						iAvailable = m_oIn.available();
					}
				}else{
					byte[] bb = new byte[iAvailable];
					m_oIn.read(bb);
					bBuffer.put(bb);
				}
				bBuffer.flip();
				byte[] aB = bBuffer.array();
				String sMsg = new String(aB, 0, aB.length, "utf-8");
				ServerFrame.m_oFrame.setMsg(sMsg);
			}

 

在这里要说一下:避免使用PrintWriter,很多新学的朋友都很喜欢用PrinterWriter,原因1很简单它不会出现乱码,但是大家想过为什么了吗,它只是用了系统默认的编码,万一发送端和接收端系统默认的编码不一致,一样会导致乱码。解决最好的办法,就是把主动权掌握在自己的手里,自己来编码、解码。

 

最后提供简单的聊天小程序(附件中),还没完完全全完成,只做了一部分,不过可以运行,客户端可以发送消息给服务器端,剩下的部分,如果有兴趣的朋友可以继续完成,如果有必要,我会把剩下的部分再完善,这样做的目的是,为了大家都能学到东西。麻雀虽小,但是内脏俱全,希望新接触的朋友好好看一下,希望对你们有积极的作用。

  • 大小: 25.9 KB
1
1
分享到:
评论
2 楼 JimmyHR 2013-04-01  
BasicTypeConverter#intToByte 里面已经说明了用处,它的用处只是将整型转换成字节。
1 楼 小马在天 2013-03-31  
   m_handler.out().write(BasicTypeConverter.intToByte(iLen));
中intToByte方法咋用的啊,啥意思?

相关推荐

    java中处理socket通信过程中粘包的情况

    本篇文章主要介绍了java中处理socket通信过程中粘包的情况,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

    Java聊天应用程序 - 创建一个基本的即时聊天应用

    在这篇Java实战博客中,我们将详细介绍如何构建一个简单的聊天应用程序,包括以下内容: 项目概述 构建服务器端 构建客户端 实现消息传输 运行聊天应用程序 总结 我们将使用Java的Socket编程来实现服务器端和客户端...

    21天学通Java-由浅入深

    第一篇 基础篇 第1章 Java简介(精彩视频:33分钟) 21 1.1 Java的平台简介 21 1.2 安装工具包 22 1.2.1 下载JDK 22 1.2.2 安装JDK 24 1.2.3 查看与设置环境变量 25 1.2.4 JDK常用命令 27 1.2.5 Java各个目录含义 28...

    由浅入深学Java—基础、进阶与必做260题 高清pdf版

    第2篇讲解了图形界面开发基础、Swing编程、事件处理、数字处理、异常处理、文件的输入与输出、反射、线程、正则表达式、封装类、容器、泛型、数据结构、数据库编程和Applet等高级技术;第3篇讲解了Socket、JSP、...

    由浅入深学Java—基础、进阶与必做260题.pdf

    第2 篇讲解了图形界面开发基础、Swing编程、事件处理、数字处理、异常处理、文件的输入与输出、反射、 线程、正则表达式、封装类、容器、泛型、数据结构、数据库编程和Applet等高级技术;第3篇讲解了 Socket、JSP、...

    java自学之道

    第一篇 基础篇 第0章 JDK安装和最简单的环境变量配置方法 第1章 Java基础概念 一、 Java基础语法 1、Helloworld.java 2、标识符 3、关键字 4、常量 5、变量 6、语句 6.1 if语句和switch语句 6.1.2 if语句举例 ...

    JAVA入门1.2.3:一个老鸟的JAVA学习心得 PART1(共3个)

    第1篇 Java语言基本语法 第1章 让自己的第一个Java程序跑起来 2 教学视频:19分钟 1.1 想要用Java改变这个世界吗? 2 1.1.1 Java有什么优势? 2 1.1.2 Java在哪儿? 3 1.2 准备好开始Java之旅 3 1.2.1 下载...

    Java入门1·2·3:一个老鸟的Java学习心得.PART3(共3个)

    第1篇 Java语言基本语法 第1章 让自己的第一个Java程序跑起来 2 教学视频:19分钟 1.1 想要用Java改变这个世界吗? 2 1.1.1 Java有什么优势? 2 1.1.2 Java在哪儿? 3 1.2 准备好开始Java之旅 3 1.2.1 下载...

    java注册网络聊天室源码-web-socket-lab:使用Tyrus的聊天服务器,JSR356的参考实现

    对象作为消息,而不是处理通过网络传输的原始数据。 我们将在几分钟内看到一个示例 这就是我们现在需要知道的所有内容,以便实现聊天应用程序。 数据模型 由于我们将创建一个聊天服务器,让我们首先使用 POJO 对消

    java专题,教学资元 共159g

    包含:socket网络编程及实战,系统学习docker,看的见的算法 7个经典应用诠释算法精髓,一站式学习Redis 从入门到高可用分布式实践,Spring Boot 2.0深度实践之核心技术篇,Scala 学习 进击大数据Spark生态圈,剑指Java面试...

    Java SE实践教程 源代码 下载

    Java SE实践教程 源代码 2010-9-13 声明:在网上找了好久才找到这个源码,真不容易啊,请大家多多支持。 2010-9-13 内容简介:此书结合具体实例讲解,通俗易懂,又不乏深度。我觉得这本书写的确实不错,堪称经典,...

    java范例开发大全源代码

     第2篇 Java数据处理  第4章 异常处理(教学视频:62分钟) 54  4.1 编译时异常 54  实例35 除0发生的算术异常(ArithmeticException) 54  实例36 数组下标越界异常(ArrayIndexOutOfBoundsException...

    java范例开发大全

    第2篇 Java数据处理 第4章 异常处理(教学视频:62分钟) 54 4.1 编译时异常 54 实例35 除0发生的算术异常(ArithmeticException) 54 实例36 数组下标越界异常(ArrayIndexOutOfBoundsException) 55 实例37 数组...

    Java范例开发大全 (源程序)

     第2篇 Java数据处理  第4章 异常处理(教学视频:62分钟) 54  4.1 编译时异常 54  实例35 除0发生的算术异常(ArithmeticException) 54  实例36 数组下标越界异常(ArrayIndexOutOfBoundsException) 55...

    Java NIO原理和使用

    Java NIO非堵塞应用通常适用用在I/O读写等方面,我们知道,系统运行的性能瓶颈通常在I/O读写,包括对端口和文件的操作上,过去,在打开一个I/O通道后,read()将一直等待在端口一边读取字节内容,如果没有内容进来,...

    Java典型模块

    第1篇 Java开发必备基础 第1章 搭建Java开发环境 1.1 Java的过去、现在和未来 1.1.1 Java的历史 1.1.2 Java的语言特点 1.1.3 Java API简介 1.1.4 Java未来发展 1.2 Java程序设计环境 1.2.1 命令行工具——JDK 6.0 ...

    Java范例开发大全(全书源程序)

    第2篇 Java数据处理 第4章 异常处理(教学视频:62分钟) 54 4.1 编译时异常 54 实例35 除0发生的算术异常(ArithmeticException) 54 实例36 数组下标越界异常(ArrayIndexOutOfBoundsException) 55 实例37 ...

    java范例开发大全(pdf&源码)

    第2篇 Java数据处理 第4章 异常处理(教学视频:62分钟) 54 4.1 编译时异常 54 实例35 除0发生的算术异常(ArithmeticException) 54 实例36 数组下标越界异常(ArrayIndexOutOfBoundsException) 55 实例37 数组...

Global site tag (gtag.js) - Google Analytics