TCP/UDP编程
对网络协议最常用的基础知识点的回忆
基础知识点详解:
第一个基础知识就是OSI模型的展示:
osi一直在说,今天来看看osi(open System Interconncetion,OSI/RM,Open System Interconnection Reference Modle):
OSI模型,即开放式通信系统互联参考模型(Open System Interconnection,OSI/RM,Open Systems Interconnection Reference Model),是国际标准化组织(ISO)提出的一个试图使各种计算机在世界范围内互连为网络的标准框架,简称OSI。
注意这几个缩写 ios(苹果公司的移动操作系统); iso(国际标准化组织) OSI(osi模型)
OSI将计算机网络体系结构(architecture)划分为以下七层;这也就是我们常说的osi七层协议:
下面的是百度百科关于各层的说明(通俗易懂)
物理层(Physical Layer): 将数据转换为可通过物理介质传送的电子信号 相当于邮局中的搬运工人
数据链路层(Datalink Layer): 决定访问网络介质的方式在此层将数据分帧,并处理流控制。本层指定拓扑结构并提供硬件寻址。相当于邮局中的装拆箱工人
网络层(Network Layer): 使用权数据路由经过大型网络 相当于邮局中的排序工人(ip协议)
传输层(Transport Layer): 提供终端到终端的可靠连接 相当于公司中跑邮局的送信职员
会话层(Session Layer): 允许用户使用简单易记的名称建立连接 相当于公司中收寄信、写信封与拆信封的秘书
表示层(Presentation Layer): 协商数据交换格式 相当公司中简报老板、替老板写信的助理
应用层(Appliication Layer): 用户的应用程序和网络之间的接口老板
数据传输
数据包的概念: 数据包是一个信息单位,作为一个整体,从网络中的一个设备传送给另一个设备。
数据包是在应用层创建的,从上向下一层一层的传递,每一层对数据包重新的组装.
数据包的格式:
- 数据包结构
数据包包含了几种不同类型的数据:
- 信息,某种类的计算机控制数据和命令
会话控制代码
数据包头
数据
报尾
- 创建数据包
数据包的创建过程是从OSI模型的应用层开始的。跨网络传输的信息要从应用层开始,往下依次穿过各层。每层都对数据包进行重新组装,以增加自己的信息(信头)。
TCP/UDP的缩写(在传输层上(第四层))
TCP(Transmission Control Protocol,传输控制协议):
UDP( User Datagram Protocol 用户数据报协议),在网络中它与TCP协议一样用于处理数据包。在OSI模型中,在第四层——传输层,处于IP协议的上一层。
IP协议: IP (Internet Protocol),处于网络层上(第三层)
网络层:
网络层负责对子网间的数据包进行路由选择。网络层还可以实现拥塞控制、网际互连等功能。
在这一层,数据的单位称为数据包(packet)。网络层协议的代表包括:IP、IPX、RIP、OSPF、ARP、RARP、ICMP、IGMP等。
传输层:
传输层是第一个端到端,即主机到主机的层次。传输层负责将上层数据分段并提供端到端的、可靠的或不可靠的传输。此外,传输层还要处理端到端的差错控制和流量控制问题。
在这一层,数据的单位称为数据段(segment)。传输层协议的代表包括:TCP、UDP、SPX等。
应用层:
应用层为操作系统或网络应用程序提供访问网络服务的接口。应用层协议的代表包括:Telnet、FTP、HTTP、SNMP等。
什么是TCP和UDP
TCP和UDP协议的区别(面试中经常问到):
- UDP
- 面向无连接,数据不安全,速度快。不区分客户端与服务端。
- TCP
* 面向连接(三次握手),数据安全,速度略低。分为客户端和服务端。
- 三次握手: 客户端先向服务端发起请求, 服务端响应请求, 传输数据
在这里在说说sockect(套接字)
- 网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。
- 通信的两端都有Socket。
- 网络通信其实就是Socket间的通信。
- 数据在两个Socket间通过IO流传输。
- Socket在应用程序中创建,通过一种绑定机制与驱动程序建立关系,告诉自己所对应的IP和port。
UDP传输
DatagramSocket类用来创建和发送UDP的Socket实例;
DatagramSocket():创建实例。通常用于客户端编程,它并没有特定监听的端口,仅仅使用一个临时的。
DatagramSocket(int port):创建实例,并固定监听Port端口的报文。
DatagramSocket(int port, InetAddress localAddr):这是个非常有用的构建器,当一台机器拥有多于一个IP地址的时候,由它创建的实例仅仅接收来自LocalAddr的报文
receive(DatagramPacket d):接收数据报文到d中。receive方法产生一个“阻塞”。
send(DatagramPacket d):发送报文d到目的地。
setSoTimeout(int timeout):设置超时时间,单位为毫秒。
close():关闭DatagramSocket。在应用程序退出的时候,通常会主动释放资源,关闭Socket,但是由于异常地退出可能造成资源无法回收。所以,应该在程序完成时,主动使用此方法关闭Socket,或在捕获到异常抛出后关闭Sock
DatagramPacket:用于处理报文,将byte数组、目标地址、目标端口等数据包装成报文或者将报文拆卸成byte数组。
DatagramPacket(byte[] buf, int length, InetAddress addr, int port):从buf数组中,取出length长的数据创建数据包对象,目标是addr地址,port端口。
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port):从buf数组中,取出offset开始的、length长的数据创建数据包对象,目标是addr地址,port端口。
DatagramPacket(byte[] buf, int offset, int length):将数据包中从offset开始、length长的数据装进buf数组。
DatagramPacket(byte[] buf, int length):将数据包中length长的数据装进buf数组。
getData():它从实例中取得报文的byte数组编码。
- 1.发送Send
- 创建DatagramSocket, 随机端口号
- 创建DatagramPacket, 指定数据, 长度, 地址, 端口
- 使用DatagramSocket发送DatagramPacket
- 关闭DatagramSocket
- 2.接收Receive
- 创建DatagramSocket, 指定端口号
- 创建DatagramPacket, 指定数组, 长度
- 使用DatagramSocket接收DatagramPacket
- 关闭DatagramSocket
- 从DatagramPacket中获取数据
- 3.接收方获取ip和端口号
- String ip = packet.getAddress().getHostAddress();
- int port = packet.getPort();
发送端的java代码:
package com.heima.socket;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
public class Demo1_Send {
/**
* * 1.发送Send
* 创建DatagramSocket, 随机端口号
* 创建DatagramPacket, 指定数据, 长度, 地址, 端口
* 使用DatagramSocket发送DatagramPacket
* 关闭DatagramSocket
* @throws SocketException
* @throws UnknownHostException
*/
public static void main(String[] args) throws Exception {
String str = "what are you 弄啥呢?";
DatagramSocket socket = new DatagramSocket(); //创建Socket相当于创建码头
//InetAddress.getByName("127.0.0.1"):要发给谁,要写对方的ip地址
DatagramPacket packet = //创建Packet相当于集装箱,,存放要发送的数据
new DatagramPacket(str.getBytes(), str.getBytes().length, InetAddress.getByName("127.0.0.1"), 6666);
socket.send(packet); //发货,将数据发出去
socket.close(); //关闭码头
}
}
UDP传输的接收端:
package com.heima.socket;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class Demo1_Receive {
/**
** 2.接收Receive
* 创建DatagramSocket, 指定端口号
* 创建DatagramPacket, 指定数组, 长度
* 使用DatagramSocket接收DatagramPacket
* 关闭DatagramSocket
* 从DatagramPacket中获取数据
* @throws Exception
*/
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(6666); //创建Socket相当于创建码头
DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);//创建Packet相当于创建集装箱
socket.receive(packet); //接货,接收数据
byte[] arr = packet.getData(); //获取数据
int len = packet.getLength(); //获取有效的字节个数
System.out.println(new String(arr,0,len));
socket.close();
}
}
对上面的代码进行优化:
发送端优化代码展示:
package com.heima.socket;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Demo2_Send {
/**
* * 1.发送Send
* 创建DatagramSocket, 随机端口号
* 创建DatagramPacket, 指定数据, 长度, 地址, 端口
* 使用DatagramSocket发送DatagramPacket
* 关闭DatagramSocket
* @throws SocketException
* @throws UnknownHostException
*/
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in); //创建键盘录入对象
DatagramSocket socket = new DatagramSocket(); //创建Socket相当于创建码头
while(true) {
String line = sc.nextLine(); //获取键盘录入的字符串
if("quit".equals(line)) {
break;
}
DatagramPacket packet = //创建Packet相当于集装箱
new DatagramPacket(line.getBytes(), line.getBytes().length, InetAddress.getByName("127.0.0.1"), 6666);
socket.send(packet); //发货,将数据发出去
}
socket.close(); //关闭码头
}
}
接收端代码优化展示:
package com.heima.socket;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class Demo2_Receive {
/**
** 2.接收Receive
* 创建DatagramSocket, 指定端口号
* 创建DatagramPacket, 指定数组, 长度
* 使用DatagramSocket接收DatagramPacket
* 关闭DatagramSocket
* 从DatagramPacket中获取数据
* @throws Exception
*/
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(6666); //创建Socket相当于创建码头
DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);//创建Packet相当于创建集装箱
while(true) {
socket.receive(packet); //接货,接收数据
byte[] arr = packet.getData(); //获取数据
int len = packet.getLength(); //获取有效的字节个数
String ip = packet.getAddress().getHostAddress(); //获取ip地址
int port = packet.getPort(); //获取端口号
System.out.println(ip + ":" + port + ":" + new String(arr,0,len));
}
}
}