Internet-TCP和UDP协议

一.概念

网络分层:
	应用层:HTTP/WebSocket(Html)、DNS、FTP、SMTP/POP3/IMAP、XMPP/MQTT、TELNET/SSH
	传输层:TCP/UDP(Socket)、DCCP、RTP、PPTP 
	网络层:IP、ICMP(ping)、IGMP、RIP		
	链路层: IP数据报封装成合适在物理层传输的帧格式
	物理层: 实现bit流在结点间传输,既与链路有关,也与传输介质有关

链路层协议MTU(最大传输单元):
	FDDI协议:4352字节
	以太网Ethernet协议:1500字节
	PPPoE(ADSL)协议:1492字节
	X.25协议(Dial Up/Modem):576字节
	Point-to-Point:4470字节

二.区别

若传输层数据大于MTU,则IP协议会分包,IP头部序号使数据包按序重组!	
TCP协议可完成数据分包与重组,数据包在576字节以内,无需IP协议分包!	

若在局域网(以太网协议),UDP数据包最好控制在1472字节以内! 
若在互联网,存在不同链路层协议,最小MTU是576字节,UDP数据包最好控制在576以内!	

TCP协议: 发送数据之前,三次握手建立连接,传输完成,四次挥手断开连接;
		实现数据分包与按序重组
		低效率,但接收数据准确
		java类库: Socket/ServerSocket

UDP协议: 直接发送数据,不建任何连接,不管对方是否收到;
		数据包无序列号,接收端不保证顺序
		高效率,但接收数据包可能丢失或乱序
		java类库: DatagramSocket/DatagramPacket

与HTTP区别:
		HTTP是在TCP连接的基础上,增加了数据封装格式,
		还添加了限制:只能客户端主动请求,服务端不能主动发送(推送)数据,
		我猜早期设计者是为了简化浏览器,毕竟早期浏览器只用来浏览器而已!			
		然而现在网页网罗一切,推送消息就必不可少,如果不断轮询服务器,显然效果差!
		虽然HTTP1.1默认长连接(即不断开TCP连接),但是服务器想主动推送,还是不行!
		因为实现HTTP协议浏览器都没有监听TCP端口,不可能知道服务器主动发了请求!
		所以出现了变相实现推送:服务器收到请求,不响应,需要推送时才响应浏览器!
		此外,Html5新协议WebSocket也是为弥补Http缺少推送而产生的!
								
		TCP则没有限制,是双向通信,只要知道对方ip端口,双方就可主动发数据(但对方须监听端口)				

三.java使用TCP协议


// TCP客户端
public class TCPClient{
	public static void main(String args[]) throws Exception{
		// 1.输入服务端IP和端口,下载文件路径
		String ip = args[0];
		int port = Integer.parseInt(args[1]);
		String filePath = args[2];
		Socket socket = new Socket(ip, port);
		// 2.建立TCP连接,发送文件路径
		new DataOutputStream(socket.getOutputStream()).writeUTF(filePath);
		// 3.接收文件名,大小,内容
		DataInputStream sin = new DataInputStream(socket.getInputStream());	
		FileOutputStream fou = new FileOutputStream(System.currentTimeMillis()+"_"+sin.readUTF());		
		long len = sin.readLong();
		int pro=0;  
		int l; 
		byte[] b = new byte[1024*1024];
		while ((l = sin.read(b)) != -1) {
			fou.write(b,0,l);
			pro += l;
			System.out.println("下载大小"+String.format("%.2f",pro/1024f/1024)+"MB, "+
								"进度"+String.format("%.2f",pro*100f/len)+"%"); 
		}       
		sin.close();
		fou.close();
		socket.close();
	}
}

// TCP服务端
public class TCPServer{
	public static void main(String arg[]) throws Exception{
		// 1.输入服务端监听端口
		String port = arg[0];
		ServerSocket serverSocket = new ServerSocket(Integer.parseInt(port)); 
		while (true) {
			// 2.死循环监听端口,等待客户端请求
			System.out.println("正在监听"+port+"端口。。。\n");
			Socket socket = serverSocket.accept();			
			// 3.TCP连接成功,接收客户端请求文件路径
			String filePath = new DataInputStream(socket.getInputStream()).readUTF();
			File file = new File(filePath);
			FileInputStream fin = new FileInputStream(file);
			System.out.println("TCP连接成功,客户端请求文件路径"+filePath);            
			// 4.发送文件
			DataOutputStream sou = new DataOutputStream(socket.getOutputStream());			
			sou.writeUTF(file.getName());				
			sou.writeLong(file.length());			
			byte[] b = new byte[1024*1024];
			int l;
			while ((l = fin.read(b)) != -1) {
				sou.write(b, 0, l);
				System.out.println("正在发送文件。。。");
			}
			System.out.println("文件发送完成\n");         
			fin.close();
			sou.close();
			socket.close();
		}
	}
}
	

四.java使用UDP协议


// UDP客户端
public class UDPClient{
	public static void main(String[] args)throws IOException{
		// 1.直接发数据(不建立连接)
		DatagramSocket dsocket = new DatagramSocket();
		byte[] sen = "你好!我是UDP客户端".getBytes("utf-8");
		dsocket.send(new DatagramPacket(sen,sen.length,InetAddress.getByName("localhost"),9999));
		System.out.println("客户端发送");
		// 2.接收数据
		DatagramPacket rec = new DatagramPacket(new byte[100],100);
		dsocket.receive(rec);	
		dsocket.close();
		System.out.println("客户端接收:" + new String(rec.getData(),0,rec.getLength()));
	}
}

// UDP服务端
public class UDPServer{
	public static void main(String[] args)throws IOException{			
		DatagramSocket dsocket = new DatagramSocket(9999);
		DatagramPacket rec = new DatagramPacket(new byte[100], 100);			
		while (true) {
			// 1.监听端口
			System.out.println("监听等待...");
			dsocket.receive(rec);   // 线程等待, 直到接收到消息				
			// 2.接收数据
			System.out.println("服务端接收:"+new String(rec.getData(), 0, rec.getLength()));
			// 3.发送数据
			byte[] sec = "你好!我是服务端".getBytes("utf-8");
			dsocket.send(new DatagramPacket(sec, sec.length, rec.getAddress(), rec.getPort()));
			System.out.println("服务端响应!");
		}
}

简书: http://www.jianshu.com/p/83330e36b4de
CSDN博客: http://blog.csdn.net/qq_32115439/article/details/55798783
GitHub博客:http://lioil.win/2017/02/19/TCP-UDP.html
Coding博客:http://c.lioil.win/2017/02/19/TCP-UDP.html