物理链路网络运输会话表示应用
物链网运会表应
实际的数据帧
TCP和UDP的异同(笔试面试)
主机:host
转换:to
网络:network
uint32_t htonl(uint32_t hostlong); //将4字节无符号整数的主机字节序转换为网络字节序,参数是主机字节序,返回值是网络字节序
uint16_t htons(uint16_t hostshort); //将2字节无符号整数的主机字节序转换为网络字节序,参数是主机字节序,返回值是网络字节序
uint32_t ntohl(uint32_t netlong); //将4字节无符号整数的网络字节序转换为主机字节序,参数是网络字节序,返回值是主机字节序
uint16_t ntohs(uint16_t netshort); //将2字节无符号整数的网络字节序转换为主机字节序,参数是网络字节序,返回值是主机字节序
IP地址类型
A类地址 | 1.0.0.0~127.255.255.255 | 2^7(网络号) | 2^24(主机号) | 已经保留不在供给 |
B类地址 | 128.0.0.0~191.255.255.255 | 2^14 | 2^16 | 名地址网管中心 |
C类地址 | 192.0.0.0~223.255.255.255 | 2^21 | 2^8 | 校园网或企业网、家庭网 |
D类地址 | 224.0.0.0~239.255.255.255 | 组播地址 | ||
E类地址 | 240.0.0.0~255.255.255.255 | 保留 |
子网掩码的使用:IP地址 & 子网掩码 --->子网网段
为了区分同一主机上的多个进程,使用端口号来进行处理
端口号是一个2字节的无符号整数存储,取值范围【0,65535】
网络通信中两个决定性因素:IP + 端口号
TCP和UDP的端口号是相互独立的
可以使用的:1024~49151,就是我们平时编写服务器使用的端口号
临时端口号:49152~65535,这部分是客户端运行时候动态选择的
TCP协议:
struct sockaddr_in sin;
sin.sin_family = AF_INET; //通信域
sin.sin_port = htons(SER_PORT); //端口号
sin.sin_addr.s_addr = inet_addr(SER_IP); //ip地址
int socket([ipv4/v6],[TCPUDP], 0);
int bind([套接字名],[地址信息] , sizeof([地址信息结构体]));
int listen([套接字名],[长度一般填128]);
int accept([套接字名], [地址信息接收指针] , [地址信息的长度]);
ssize_t recv([套接字名], void *buf, sizeof (buf), [阻塞或非阻塞]);
ssize_t send([新套接字名], void *buf, sizeof (buf), [阻塞或非阻塞]);
int connect([套接字名] ,[对端地址信息结构体], sizeof([对端地址信息结构体]));
服务器端模型
客户端模型:
1.cfd = socket(AF_INET, SOCK_STREAM, 0);
//2.1 填充地址信息结构体
struct sockaddr_in cin;
cin.sin_family = AF_INET; //通信域
cin.sin_port = htons(CLI_PORT); //端口号
cin.sin_addr.s_addr = inet_addr(CLI_IP); //ip地址
2.bind(cfd, (struct sockaddr*)&cin, sizeof(cin))
//3.1 填充服务器地址信息结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET; //通信域
sin.sin_port = htons(SER_PORT); //服务器端口号
sin.sin_addr.s_addr = inet_addr(SER_IP); //服务器ip地址
3.connect(cfd, (struct sockaddr*)&sin, sizeof(sin) //将套接字文件描述符连接到addr指向的地址空间中
while(1)
{
4.send(cfd, buf, strlen(buf), 0);
5.recv(cfd, buf, sizeof(buf), 0);
}
6.close();
UDP协议:
ssize_t recvfrom([套接字名], buf[起始地址], sizeof(buf), [阻塞], [对端地址信息结构体],
[对端地址信息结构体大小]);
ssize_t sendto([套接字名], buf[起始地址], sizeof(buf), [阻塞], [对端地址信息结构体],
[对端地址信息结构体大小]);
服务器端模型:
1.sfd = socket(AF_INET, SOCK_DGRAM, 0)
//2.1 填充地址信息结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET; //通信域
sin.sin_port = htons(SER_PORT); //端口号
sin.sin_addr.s_addr = inet_addr(SER_IP); //ip地址
2.bind(sfd, (struct sockaddr*)&sin, sizeof(sin)
while(1)
{
3.recvfrom(sfd, buf, sizeof(buf), 0, (struct sockaddr*)&cin, &addrlen);
4.sendto(sfd, buf, strlen(buf), 0, (struct sockaddr*)&cin, sizeof(cin))
}
5.close(sfd);
客户端模型:
1.cfd = socket(AF_INET, SOCK_DGRAM, 0);
//2.1 填充地址信息结构体
struct sockaddr_in cin;
cin.sin_family = AF_INET; //通信域
cin.sin_port = htons(CLI_PORT); //端口号
cin.sin_addr.s_addr = inet_addr(CLI_IP); //ip地址
2.bind(cfd, (struct sockaddr*)&cin, sizeof(cin)
//填充服务器的地址信息结构体
struct sockaddr_in sin; //接受对端地址信息
sin.sin_family = AF_INET; //服务器的通信域
sin.sin_port = htons(SER_PORT); //服务器端口号
sin.sin_addr.s_addr = inet_addr(SER_IP); //服务器ip地址
while (1)
{
3.//将数据发送给服务器
sendto(cfd, buf, strlen(buf), 0, (struct sockaddr*)&sin, sizeof(sin));
4.//接受服务器发来的消息
recvfrom(cfd, buf, sizeof(buf), 0, NULL, NULL);
}
5.close(cfd);
TCP和UDP基础通信模型注意事项
1> 无论是TCP还是UDP通信中,服务器端必须要绑定ip地址和端口号,以便于让客户端找到该服务器。对于客户端而言,可以绑定也可以不绑定,如果绑定了,则使用自己绑定的ip和端口号。如果没有绑定,则系统会自动绑定一个当前的IP地址和一个随机的端口号供客户端使用。
2> 对于TCP通信而言,可以使用recv和send进行通信,也可以使用read、write进行通信,还可以使用sendto和recvfrom进行通信,都没有问题。
3> 对于UDP通信而言,如果当前端只是用于接收数据,不发送数据,可以使用recvfrom、recv、read进行接收;如果当前端接收数据后还要发送数据给对端,则需要使用recvfrom进行接收数据,顺便将对端地址信息结构体接收过来。
4> UDP中是否可以使用connect函数呢?
答,可以使用。当UDP服务器端使用connect会跟指定的客户端建立一个唯一的通道。其他客户端就不能再进行通信了。如果想要断开连接,需要再次使用connect函数,并且将地址信息结构体中的family设置成AF_UNSPEC.
好处:1、能够提供数据传输效率
例如:A和B同时向服务器发送消息,但是A发送的消息较大,需要较长的时间,发送过程中可能会出现时间片用完,此时B向服务器发送消息,导致,服务器处理消息时,消息混乱。这时就可以先单独跟A建立连接,等所有数据传输结束后,再跟B通信
2、传输性能高
一般的UDP通信:获取对端地址信息 --> 将信息加载到内核 ---> 数据收发 --->获取对端地址信息 --> 将信息加载到内核 ---> 数据收发 --->获取对端地址信息 --> 将信息加载到内核 ---> 数据收发 --->....
UDP建立连接后:获取对端地址信息 --> 将信息加载到内核 ---> 数据收发 --->数据收发 --->数据收发 --->数据收发 --->数据收发 --->数据收发 --->