tcp/ip高效编程总结
1.客户端-服务器结构
客户端-服务器结构的物理部署分为三类:
(1)在同一台机器上:理想环境,只要压力不大,分组不会丢失、延迟和乱序,是理想的测试环境,可以用作评估客户端和服务器端程序的原始性能;
(2)在同一局域网内:接近理想环境,分组很少丢失、乱序,但是有延迟;
(3)在广域网内:分组丢失、重传、重复、乱序比较常见。
2.基本套接字API
(1) sys/socket.h、winsock2.h:SOCKET socket(int domain, int type, int protocol)
成功时返回套接字,失败时返回-1(linux),INVALID_SOCKET(windows)
domain:通信域,AF_INET为互联网,AF_LOCAL或AF_UNIX为统一台机器上进程间通信;
type:套接字类型,
SOCK_STREAM为可靠、全双工、面向连接的字节流,对应于tcp;
SOCK_DGRAM为不可靠、尽力而为的数据报服务,对应于udp;
SOCK_RAW对ip层某些数据访问;
protocol:对tcpip来说,这个字段通常由套接字类型隐含说明,参数默认被设置为0。
(2) sys/socket.h、winsock2.h:int bind(SOCKET s, const struct sockaddr* local, int local_len)
成功时返回套接字,成功时返回0,失败时返回-1(linux),SOCKET_ERROR(windows)
s:套接字描述符,由socket函数返回;
local:绑定的地址和端口,对AF_INET来说,对应的是struct sockadd_in;
local_len:peer结构体大小;
(3) sys/socket.h、winsock2.h:int listen(SOCKET s, int backlog)
成功时返回套接字,成功时返回0,失败时返回-1(linux),SOCKET_ERROR(windows)
s:套接字描述符,由socket函数返回;
backlog:排队等待应用程序接受的连接最大数量;
(4) sys/socket.h、winsock2.h:int accept(SOCKET s, struct sockaddr* peer, int* peer_len)
成功时返回套接字,成功时返回0,失败时返回-1(linux),INVALID_SOCKET(windows)
s:套接字描述符,由socket函数返回;
peer:对等实体地址和其他一些信息,对AF_INET来说,对应的是struct sockadd_in;
peer_len:peer结构体大小;
(5) sys/socket.h、winsock2.h:int connect(SOCKET s, const struct sockaddr* peer, int peer_len)
成功时返回套接字,成功时返回0,失败时返回-1(linux),非0(windows)
s:套接字描述符,由socket函数返回;
peer:对等实体地址和其他一些信息,对AF_INET来说,对应的是struct sockadd_in;
peer_len:peer结构体大小;
(6) sys/socket.h:int read(SOCKET s, void* buf, size_t len, int flags)
int write(SOCKET s, const void* buf, size_t len, int flags)
winsock2.h: int recv(SOCKET s, void* buf, size_t len, int flags)
int send(SOCKET s, const void* buf, size_t len, int flags)
成功时返回字节数,失败时返回-1(linux),-1(windows)
s:套接字描述符,由socket函数返回;
buf:发送数据存储;
len:发送字节数;
flags:与系统有关,linux和windows都支持MSG_OOB、MSG_PEEK、MSG_DONTROUTE
(7) sys/socket.h、winsock2.h:int recvfrom(SOCKET s, void* buf, size_t len, int flags,struct sockaddr* from, int from_len)
int sendto (SOCKET s, const void* buf, size_t len, int flags,struct sockaddr* to, int to_len)
成功时返回字节数,失败时返回-1(linux),-1(windows)
s:套接字描述符,由socket函数返回;
buf:发送数据存储;
len:发送字节数;
3.面向连接和无连接协议
面向连接和无连接指的是协议,不是物理介质。指的是协议的分组寻址是否独立寻址,协议是否需要维护分组之间的状态。这里的分组是协议分组,不是指应用程序要传输的数据大小。
UDP通过只向IP层增加两项功能:增加可选的校验和来检测数据的损坏情况;添加端口区分上层应用;
TCP通过向IP层增加三项功能实现了可靠性:增加可选的校验和来抵抗数据损坏;为每字节增加序列号抵抗乱序;增加确认——重传机制抵抗丢失。
4.子网与CIDR
传统上将ip地址分为5类,称为分类编址:
A类:7bit网络24bit主机 0.0.0.1——127.255.255.255
B类:14bit网络16bit主机 128.0.0.1——191.255.255.255
C类:21bit网络8bit主机 192.0.0.1——223.255.255.255
D类:多播1110开头
E类:保留4bit1开头
为了使用较小路由表,使单个网络ID的Ip地址空间得到有效利用,而且享有每个网段具有独立网络ID时路由的便捷性,我们需要从外部主机看是单个网络,从内部主机看是多个网络。实现这种功能的机制就是子网划分。
5. tcp是一种流协议
对tcp应用程序来说,没有分组的概念,应用程序需要自己确定包的大小和边界。有三种方式确定包大小:
固定包大小,所有分组的包大小相同;
使用记录结束标志,这需要在发送端对报文主题中的结束标志进行转义,接收端扫描整个报文;
使用报文头来指定报文大小,这种方式必须小心编译器本身对数据封装的填充、42. 1。
6. UDP的使用注意实现
对于简单的请求、应答程序来说,UDP的性能会显著优于TCP。因此可以考虑使用UDP协议作为基于事务的应用程序的支撑协议。
健壮的UDP程序必须提供:合理时间内没有收到应答则重传;应答和请求的正确匹配;流量控制;拥塞控制。这里合理的时间要靠RTO定时器来计时,但是大小就是需要根据网络条件来调整了。应答和请求的正确匹配可以使用序列号的方式来保证。TCP的滑动窗口是实现流量控制的常见方式。·
应该避免为了使用UDP而在用户层实现TCP的可靠性,这可能不会导致性能比TCP好,而且也可能会出错。如果既想拥有TCP的可靠性,又想使用UDP差不多的事务性能,可以使用T/TCP。
7.TCP的可靠性
TCP是一个端到端协议,保证的是对等实体间的可靠性,也就是tcp层到tcp层间的可靠性。只要两个对等的tcp之间是连接的,tcp就能保证将数据可靠(按序、无损)的传送。这里的受损是指在因特网校验和的条件下未受损。对等应用程序间的可靠性需要应用程序自己来保证。即,从应用程序A通过tcp发送到应用程序B,凡是A的tcp层收到ACK的都表示已经可靠的传输到B的tcp层;凡是B的应用程序收到的数据都是按序且未受损的。
连接中断的三种情况:
(1) 永久或临时的网络中断:;
(2) 对等的应用程序崩溃:;
(3) 对等的应用程序所在主机崩溃:;
8.