java网络通信
一、tcp和udp的区别
1)tcp面向连接(connect,三次握手),udp无连接2) tcp保证可靠(要求对端确认),udp不提供可靠的实时传输
3)tcp提供流量控制(通告窗口),udp无流量控制
当然,udp实时,开销小
二、tcp深入
1.tcp客户端的流程:
socket()——>connect()——>write() or read() 完成交互——> close()
其中,connnect发起主动连接;客户端不需要绑定端口,需要绑定服务器端的ip,(udp里面是数据DatagramPaket自己封装ip和端口)系统会进行自动分配
2.tcp服务器端的流程:
socket()——>bind()——>listen()——>accept()——>read() or write()完成交互——>close()
其中,bind()绑定ip和端口;listen()则把一个未连接的套接口转换成一个被动套接口(创建一个套接口后,被假设为一个主动套接口);accept()等待接收;close()关闭套接口,具体的说,close操作只是使得相应套接字的引用计数减一,只有当计数减少为0的时候,才会触发tcp客户端向服务器发送终止连接请求(主要考虑多线程)。
3,TCP半关闭
如果是半关闭(主要因为tcp是全双工的),不使用close,而是利用shutdown(SHUR_WR)
int shutdown(int sockfd,int howto);其中howto可以为
SHUT_RD,不能接收数据,当前接收缓冲区的都被丢弃,但仍可写,可以发出数据
SHUT_WR,不能发出写数据,但仍可读,留在发送缓冲区的数据将被发送到。这成为半关闭。
SHUT_RDWR,同时关闭读和写。
另外,close只是令计数减1,而shutdown后其他进程将无法利用此套接字通信。
4,三次握手和四次握手
tcp建立连接:三次握手:
以客户端主动建立连接为例:
1)客户端发送一个SYN J [connect 函数]
2)服务器返回一个ACK J+1,发送一个SYN K [accept 函数,客户端的connect返回]
3)客户端发挥一个ACK K+1 [accept函数,服务器端的accept函数返回]
三次握手的原因:防止失效的连接请求报文突然又传送放到服务器。设想这么一种场景:客户端第一次发送的连接请求并没有丢失,而是网络问题导致延迟到达服务器,服务器以为是客户端又发起的新连接,于是同意,并向客户端发挥确认,而客户端不予理会,服务器就一直等待客户端发送请求,导致资源浪费。
tcp释放连接:四次握手:
1)一个进程调用close发送FIN,表示数据发送完毕。
2)另一端在收到FIN后,执行被动关闭,同时发回确认。
3)一段时间后,另一端调用close发送FIN
4)接收到FIN的原发送端,对它进行确认。
四次握手的原因:TCP是全双工的,必须保证每个方向的连接都被释放掉。
5,利用java语言实现TCP连接
java利用serverSocket代表服务器端的套接字,其构造函数中同时完成bind绑定
Socket代表客户端的套接字
package com.bobo.interview; import java.io.IOException; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; public class MyServer { private final static int PORT=30000; /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { ServerSocket server=new ServerSocket(PORT); while(true){ Socket s=server.accept(); //如果有连接请求,上面的accept函数返回 PrintStream ps=new PrintStream(s.getOutputStream()); ps.println("您好,您收到了服务器的信息。。。。"); ps.close(); s.close(); } } }
package com.bobo.interview; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; public class MyClient { private final static int PORT = 30000; private final static String ip = "127.0.0.1"; /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { Socket client = new Socket(ip, PORT); BufferedReader br = new BufferedReader(new InputStreamReader( client.getInputStream())); System.out.println(br.readLine()); br.close(); client.close(); } }
java里面使用shutdownInput或者shutdownOutput来实现半关闭
二、udp深入
udp没有TCP那么复杂的流程,java里面利用DatagramSocket达标udp的套接字,其本身只是码头,负责数据发送,不维护状态;
UDP严格的说,没有服务器端和客户端之分
通常创建充当服务器端的DatagramSocket的时候,需要指定端口,充当客户端则使用随机端口
DatagramSocket发送和接收数据采用的是DatagramPacket,代表数据报,数据报本身指定发送的ip和端口。
一下是udp通信的java实现:
package com.bobo.interview; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class UDPserver { // 服务器端需要指定端口 private static int PORT = 4096; // 指定接收数据的数据报 private static int DATA_LEN = 4096; private static byte[] inBuff = new byte[DATA_LEN]; private static DatagramPacket inPacket = new DatagramPacket(inBuff, inBuff.length); // 指定发送数据的数据报 private static DatagramPacket outPacket; // 构造发送的数据 static String outData = "服务器端发送的数据"; /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { DatagramSocket udpServer = new DatagramSocket(PORT); // 利用循环接收数据 for (int i = 0; i < 1000; i++) { udpServer.receive(inPacket); System.out.println(inBuff == inPacket.getData()); System.out.println(new String(inPacket.getData())); byte[] sendData = outData.getBytes(); outPacket = new DatagramPacket(sendData, sendData.length, inPacket.getSocketAddress()); udpServer.send(outPacket); } } }
package com.bobo.interview; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; public class UDPclient { // 服务器端需要指定端口 private static int PORT = 4096; private static String ip = "127.0.0.1"; // 指定接收数据的数据报 private static int DATA_LEN = 4096; private static byte[] inBuff = new byte[DATA_LEN]; private static DatagramPacket inPacket = new DatagramPacket(inBuff, inBuff.length); // 指定发送数据的数据报 private static DatagramPacket outPacket; /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { DatagramSocket udpClient = new DatagramSocket(PORT); outPacket = new DatagramPacket("客户端发送的数据".getBytes(), "客户端发送的数据".getBytes().length, InetAddress.getByName(ip), PORT); udpClient.send(outPacket); udpClient.receive(inPacket); System.out.println(new String(inPacket.getData())); } }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。