转:http://xzc520.iteye.com/blog/780617
java.net.NetworkInterface 提供了访问主机所有接口信息,etho0 lo0等
java.net.InetAddress
其它方法参看 java api 文档,掌握这两个类的使用。
TCP套接字
Socket ServerSocket
一个TCP 连接是一条抽象的双向信道,两端分别由IP地址和端口号确定。与电话相似.
示例:参看源码
客户端
a) 建立一个TCP连接,通过创建Socket实例并指定主机和端口.
b) 通过IO流传传输数据
c) 关闭连接.
服务端
a) 创建一个ServerSocket实例并指定本地端口。
b) 循环 调用accept()方法 ,并通过IO流传输数据
c) 关闭客户端连接。
UDP 套接字
DatagramPacket DatagramSocket
在IP协议的基础上增加了端口,对数据传输中可能产生的数据错误进行了检测,并抛弃已经损坏的数据。包裹和信件相似.
示例:参看源码
客户端
a) 创建一个DatagramSocket实例,可以选择本地地址和端口号进行设置。
b) 使用DatagramSocket类的send()和receive()方法来发送和接收DatagramPacket实例,进行通信。
c) 通信完成关闭.DatagramSocket.close();
服务端
a) 创建一个DatagramSocket实例,指定本地端口,并可以选择指定本地地址,
b) 使用DatagramSocket类的receive()方法来接收一个DatagramPacket实例。
c) 使用send()和receive()方法 来与客户端进行通信。
数据的发送和接收
编码
信息编码对于byte int long char 等
对于超过一个字节的数据类型,需要知道字节顺序。
字节发送顺序 整数右边开始,由低位到高位发送,little-endian
左边开始,由高位到低位发送big-endian
long lnum = 123456787654321L
十六进制 0x0000704885F926B1
确定发送顺序
big-endian 0 0 112 72 133 249 38 177
little-endian 177 38 249 133 72 112 0 0
确定是否有符号
对于有符号整型,值以二进制补码`具体关于编码知识,可以参考更多资料。
ByteArrayOutputStream
DataOutputStream
writeByte()
wirteShort()
writeInt()
writeLong()
以上的方法将整数以适当大小的二进制补码的形式写到流中。 ]
字符串和文本
在一组符号与一组整数之间的映射称为编码字符集(coded character set)
常用的字符编码
ASCII 将英语字母,数字,标点符号以及一些特殊字符映射成0-127的整数.
Unicode
ISO-8859-1
Utf-8
UTF-16BE
GBKGB2313
BIG5
…
String
getBytes() -default charset
getBytes(“UTF-8”)
通过先将字符串转换成独立的字节,再将其写到流中的方式,把String写入OutputStream
还要指定编码方式。
位操作:布尔值编码
组合输入输出流
利用BufferdOutputStream 对OutputStream进行包装,就可以实现缓冲功能,提高效率
还有很多不同的包装类对流进行操作,详细查阅java.io.*包API文档。
成帧与解析
成帧是用来解决接收端定位消息首尾位置的问题。编码成文本,多字节二进制或是两者结合的信息,应用程序协议必须指定消息接收者如何确定消息已完整接收。
DatagramPacket 有指定长度
Tcp套接字没有边界概念,从套接字读取更多字节会出现
一 接收者阻塞等待 且 无法处理接收到的消息 一旦接收者在等待响应,则会死锁。
二 如果信道中还有其它消息,接收者会将后面消息的一部分甚至全部读到第一条消息中去,发生协议错误。
两个方法让接收者准确地找到消息的结束位置
基于定界符(delimiter-based): 消息的结束由一个唯一标记(unique marker) 发送者在传输完数据后显示添加一个特殊字节序列,这个特殊字节序列不出现在传输的数据中。消息本身不能包含定界字符,如果需要可以利用填充(stuffing)技术将出现的定界字符进行修改,接收者扫描定界符时,能识别出修改的数据。利用填充技术发送者和接收者都要扫描消息。
显式长度 explicit length: 在变长字段或消息前附加一个固定大小的字段,用来指示该字段或消息中包含了多少字节。
参看源码中以下实现。
Framer
DelimFramer
LengthFramer
构建和解析协议消息
自定义协议的时候用到一些技术,举一个投票的实例来说明协议的定义过程.
一个简单投票协议,包括两种请求
查询(inquery)
客户端发送投票人ID,服务端返回 候选人ID和给定候选人票数.
投票(voting)
同上
几个用到的类 ,参数源码
消息类 指定了消息的类结构
VoteMsg 类,消息的结构类。
VoteMsgCoder 接口,用于对消息传输进行编码解码,分别用VoteMsgBinCoder 和 VoteMsgTextCoder 来实现接口,表示二进制编码或文本编码。
VoteService VoteServiceImpl 业务部分
TCPClient TCPServer 用于信息的发送和接收,需要对信息进行编码和解码,还需要用
到成帧技术。
UDPClient UDPSesrver
多任务处理
迭代服务器 处理完第一个客户请求之后,才会处理其它客户请求。
一客户端一线程 服务端中,为每个连接都创建一个新的线程来处理。
写一个处理类实现Runnable接口,用于处理客户端请求。
当有客户端连接的时候启动一个处理客户端的线程,并记录下线程的名字。
线程池 当线程数量过大时,系统会花费大量时间来处理上下转换和线程管理,没时间对客户请求进行处理。限制总线程数并重复使用线程可以解决些问题。创建一个固定大小线程组成的线程池。可以利用ExecutorService
newCachedThreadPool()
newFixedThreadPool()
newSingleThreadPool();
更多用法请参考java并发包的内容。
阻塞和超时 – 对于read(),accept(),receive()等方法会造成阻塞。
限制客户端访问时间,利用setSoTimeout()等方法来处理阻塞。
多接收者---网络提供了复制数据包的工作,而不是发送者,
单播 一对一的通信方式
多播 消息只是发送给一个多播地址,网络只是将数据分发给那些表示想要接收发送到该多播地址的数据的主机.只有UDP套接字允许广播和多播. 多播接收者需要加和一个组。
多播与单播主要区别是地址形式.IPV4 224.0.0.0-239.255.255.255 IPV6 是以FF 开头.
广播 (本地)网络中的所有主机 都会接收到一份数据副本,广播UDP数据报文和单播的报文相同,不同的是广播的地址不是常规的IP地址.IPV4 255.255.255.255
控制默认行为
Keep-Alive TCP协议提供了一种keep-alive的机制
发送和接收缓冲区大小 创建一个Socket或者DatagramSocket实例,操作系统就必须为其分配缓存区以存放接收和要发送的数据。
超时 i/o操作不能立即完成就会阻塞等待,设置最大阻塞时间,一旦超过就抛出异常。
地址重用 需要对多个套接字绑定到同一个套接字地址,或对于多播同一个主机上有多个应用程序加入了相同的多播组。这样就需要能够与正在使用的地址进行绑定的能力,要用到地址重用,setReuseAddress(true)
消除缓冲延迟时间 缓冲过程中会造成延迟,可以人为关闭。setTcpNoDelay().
紧急数据 可以优先到达接收端的数据。 setUrgentData(int data)….
关闭后停留 通过setSoLinger()方法 在close()的时候阻塞一段时间让缓冲区数据发送完成或者超时进行处理。
广播许可 java默认情况是可以广播的
通信等级 相当于数据在信息传输中具有的等级,至于标记数量和意义是取决于IP协议的版本。
基于性能的协议选择 setPerformancePreferences(int connectionTime,int latency,int bandwidth)
关闭连接 客户端关闭表示通信已经完成,Http是在服务端进行关闭。