您的位置:首页 > 理论基础 > 计算机网络

【Socket】TCP协议、UDP协议的Java入门示例

2018-03-20 22:50 417 查看

TCP(Transmission Control Protocol)传输控制协议

面向连接,可靠的基于字节流的传输通信协议,每次通信双方都需要提前建立连接,因此需要三次握手(以下情景均以客户端为数据发出方,服务端为数据接收方)

第一次【客户端进入SYN_SEND状态】

客户端向服务端发送syn包,然后等待服务端回话。

李四:“喂,是张三吗?”

第二次【服务端进入SYN_RECV状态】

服务端收到syn包后,服务端向客户端发送syn+ack包,然后等待客户端回话。

张三:“我是张三,您是李四?”

第三次【双方都进入ESTABLISHED状态】

客户端收到syn+ack包,确认服务端收到了syn包,然后将ack包发送给服务端进行确认。

李四:“我是李四,我有些事情要说,……”

第三次结束后,客户端即开始向服务端传输数据,直到传输完毕后,进行四次挥手结束这个过程。

第一次【客户端向服务端发起请求:我要挂断连接了】

客户端向服务端发送FIN=1的请求,要求断开。

李四:“那就说到这里,我忙去了”

第二次【服务端收到客户端的请求,回复:客户端可以挂断连接】

服务端向客户端发送ACK=1进行确认。

张三:“去吧,这件事我知道了”

第三次【服务端首先断开与客户端的连接,回复:服务端已经准备好】

服务端向客户端发送FIN=1的请求,准备好断开连接了。

张三:“拜拜”

第四次【客户端收到服务端的请求,回复:收到】

客户端向服务端发送ACK=1的请求,然后断开链接,服务端收到后也断开了连接

李四:“拜拜”(挂断)

TCP的Java示例

运行行时,先开启服务端,再开启客户端

可以发送被序列化的对象,常用Map集合进行封装,或者用Json或Base64转码的字符串

服务端前两步骤通常放在一个主线程的循环中,没有请求时,程序停在accept()方法,一旦接收到请求,后续创建线程,在线程中完成第三步开始的步骤

@Test
public void serverTCP() {
//服务端
try {
//1、创建通信对象,指定端口
ServerSocket ss = new ServerSocket(8000);
//2、监听客户端请求
Socket s = ss.accept();//当前线程进入阻塞状态,等待中
//3、开启输入流,接收消息
InputStream is = s.getInputStream();//发送方的信息都在s对象中
//4、读取接收到的信息
ObjectInputStream ois = new ObjectInputStream(is);
List<String> list = (List<String>) ois.readObject();
for (String str : list) {
System.out.print(str);//输出
}
//5、关闭资源,严格按照先开后关原则关闭,顺序不能改变
ois.close();
is.close();
s.close();
ss.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}

@Test
public void clientTCP() {
//客户端
try {
//1、创建通信对象,指定接收方的地址,IP和端口
Socket s = new Socket("127.0.0.1", 8000);
//2、开启输出流,发送请求
OutputStream os = s.getOutputStream();
//3、准备消息
List<String> list = new ArrayList<>();
list.add("TCP");
list.add("测试");
//4、发送消息
ObjectOutputStream oo = new ObjectOutputStream(os);
oo.writeObject(list);
oo.flush();//刷新缓存,信息开始发送
//5、关闭资源,严格按照先开后关原则关闭,顺序不能改变
oo.close();
os.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}


UDP(User Datagram Protocol)用户数据报协议

面向事务,适用于可靠性不高,延迟小的传输协议中,如常见的网络直播,在线视频,在线音频,语音等,由于该协议是一种无连接的传输层协议,传输效率高,可靠性不好,网络环境不是很好时容易出现中断,如视频暂停缓冲,语音模糊

发送方只关心谁来请求数据,然后将数据丢出去,至于数据是否完整无损的抵达接收方,不去判断

至于发送方如何得到是谁需要请求数据,这些请求可以通过接收方的APP,通过TCP连接到服务端就可以很轻松的就可以得到了,然后发送方每隔一段时间更新发送的数据到接收方缓存,就可以完成在线直播了

相当于大学上课的情景,老师为发送方,只管讲课,醒着的同学听到考试的重点,做了笔记,还有些睡着的同学什么也没听到,老师当然不会走到那些学生面前叫醒然后重新强调一遍,老师会继续讲下去,一个又一个的知识点就讲过去了

UDP的Java示例

运行时,先开启接收方,再开启发送方

【无论服务端还是客户端,都可以是接收方和发送方,比如开直播:Up主(发送方)与B站(接收方),B站(发送方)与粉丝(接收方)】

由于接收方不知道发送方的数据报的信息,接收方创建数据报时,应该大于发送方的数据容量,或者双方约定好固定的容量。

@Test
public void sendUDP() {
//发送方
try {
//1、创建发送的信息
List<String> list = new ArrayList<>();
list.add("UDP");
list.add("测试");
//2、创建输出流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(list);
//3、信息存入流中
oos.flush();
byte[] b = baos.toByteArray();
if (b == null) return;//不能发送null
//4、创建数据报,数据,长度,接收方的目标地址,端口
DatagramPacket dp = new DatagramPacket(
// b.length=73
b, b.length, InetAddress.getByName("127.0.0.1"), 8000);
//5、创建通信对象
DatagramSocket ds = new DatagramSocket();
//6、发送数据
ds.send(dp);
//7、关闭资源,严格按照先开后关原则关闭,顺序不能改变
ds.close();
oos.close();
baos.close();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

@Test
public void receiveUDP() {
//接收方
try {
//1、创建通信对象,设置监听端口
DatagramSocket ds = new DatagramSocket(8000);
//2、创建数据报
byte[] bytes = new byte[1024];
//最大和虚拟机配置有关,默认21_1917_2080,接收时,设置的长度不足会抛出EOF异常
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
//3、将接收到的数据写入数据报
ds.receive(dp);
//4、创建流转换为对象
ByteArrayInputStream bais = new ByteArrayInputStream(dp.getData());
ObjectInputStream ois = new ObjectInputStream(bais);
//5、获取数据
List<String> list = (List<String>) ois.readObject();
for (String str : list) {
System.out.print(str);//输出
}
//6、关闭资源,严格按照先开后关原则关闭,顺序不能改变
ois.close();
bais.close();
ds.close();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: