网络编程小知识
PDU
协议数据单元,有隐藏size上限,如果应用程序的包超过指定上限会被划分为多个PDU发送
TCP不提供记录结束标记,需要应用程序自己提供,比如http的\r\n
编写TCP协议需要注意IPV4和IPV6的兼容性,可以在应用程序中实现协议无关性。
getaddrinfo
多线程的socket编程不能依赖于标准的errno变量,在多线程中,error通过返回值而不是errno的方式通知调用者。
出于网络安全的考虑,应当使用strncpy、strncat、snprintf替代无缓冲区检查的字符串函数,避免黑客的字符串溢出攻击。
sockaddr和sockaddr_in在传给函数做参数的时候必须强转指针类型,是因为早期的套接字接口产生时还没有void*指针。
对广播地址执行ping命令,可以获取子网中所有ip信息
绕过TCP和UDP,直接使用IPV4和IPV6,被称为原始套接口编程
ping使用ICMP协议,ICMP是TCP的补充协议,也是一种传输层协议。
tcpdump使用DLPI(数据链路层接口)或者BPF(BSD分组过滤器,提供访问数据链路层接口)协议,使用数据链路层协议。
一个udp套接字是由一个二元组来标识的,具备不同的源IP和源端口,但具有相同的目的IP和目的端口号的数据包将通过相同的套接字被定向到同一个目的进程。
一个tcp套接字是由一个四元组标识的,具备不同的源IP和源端口,但具有相同的目的IP和目的端口号的数据包将被定位到不同的套接字。
udp是一种无连接的协议,因为udp的客户端和服务器无需维持长久的关系,一个客户端可以使用一个套接字向不同的服务器发送消息,一个服务端也可以使用同一个套接字接收来自不同客户端的消息。
TCP估算客户端到服务器往返花费时间RTT的算法是动态的,因为随着负载的不同,往返花费时间是动态变化的。
关闭连接的FIN消息除了关闭单向连接还具有结束文件的作用,收到FIN的端会把FIN作为文件结束符传递给接收应用进程(放在已排队等待接收的任何数据之后)。表示应用程序在连接上再也接收不到额外数据,但TCP还是可以接收消息的,想想后面的ACK消息是怎么接收的。
TCP是没有消息边界的,UDP具有长度,可以认为每个UDP数据报都是一条消息。
大多数情况下是客户端主动关闭连接,而HTTP协议是服务端主动关闭连接。
TCP连接有11种状态,使用netstat可以显示所有这些状态。
TIME_WAIT状态的时间是MSL(最常分节生命期)的两倍,有时称为2MSL,MSL是IP数据报在互联网中能生存的最长时间。RFC1122建议MSL是2分钟,而berkeley的实现传统上是30s。
存在TIME_WAIT状态的理由:
1。实现终止TCP全双工连接的可靠性,(假设主动关闭的一端是客户端,被动关闭的一端是服务端)假设最终的ACK丢失,服务端将重发最终的FIN,必须维持状态以便重发最终的ACK。如果不维护状态,客户端将响应以RST分节,这个分节被认为是某种错误。TIME_WAIT存在的目的是为了解决关闭连接的任何一个分节可能丢失的状况。
2.允许老的重复分节在网络中消逝,假设一个连接在关闭后又以相同的IP和端口号建立新的连接,必须要保证老的连接的重复分组在网络中已经消失,避免被认为是新的连接的分组。为了做到这点,TCP不能给出于TIME_WAIT阶段的连接建立新的化身连接(指以一样的IP和端口建立连接)。
UNIX系统有保留端口的概念,任何小于1024的端口都只能分配给超级用户进程的套接口。即周知端口的启动必须有超级用户权限。
TCP有一个MSS,通告对方在每个分节中可以发送的最大TCP字节量,避免在经过路由的时候被分片。
TCP的发送是异步的,write返回仅仅表示数据拷贝到了发送缓冲区,并不代表对端收到了消息。
字节流套接字上的read和write的表现不同于通常的文件I/O,字节流套接字上read和write实际读取和写入的字节可能比要求的少,这可能是套接字的缓冲区达到了极限,而不是错误,此时需要做的是再次调用read和write。
RST表示指定的对端的端口没有进程在等待连接。
connect失败时,套接字不再可用,该套接字必须被关闭,不能再次connect该套接字,再次连接需要关闭该套接字,重新调用socket。
connect函数调用前不一定非得调用bind,如果有必要,内核将分配一个临时端口,server一般会调用bind,因为要绑定一个周知端口供客户端连接。
当有客户端发送SYN时,服务器首先在未完成连接队列建立条目,如果三次握手完成,把该条目从未完成队列转移到已完成队列的队尾。当调用accept的时候,从已完成队列的队首返回一个连接(三次握手在accept之前已经完成,accept是从已建立连接的队列中取出队首)。
listen函数只做两件事
1.使用socket创建一个套接字时,内核默认是主动套接字,将调用connect发起连接的客户端套接字,而listen将未连接的套接字转换为被动套接字,等待其他socket的连接请求。同时TCP的状态CLOSED状态转换到LISTEN。
2.设置内核为此套接口排队的最大连接数。
TCP套接字的close接口给socket打上已关闭的标记,应用进程不能在此套接字上read和write,TCP会尝试发送已排队的所有数据,然后按照正常的序列关闭TCP连接。
获取与套接口关联的本地协议地址getsockname,getsockname也可以对未绑定的套接字使用,获取与套接口关联的远程协议地址getpeername,知道客户协议地址的另一个方法是accept。