几个结论:
1. linux查看tcp缓冲区参数命令:
cat /proc/sys/net/ipv4/tcp_wmem # 写缓冲区大小
4096 16384 4194304 # 分别表示最小值,默认值,最大值
cat /proc/sys/net/ipv4/tcp_rmem # 读缓冲区大小
4096 87380 6291456 # 同上
其中默认值只是一个参考值,操作系统基本都会动态设置读写缓冲区的大小,且在每一次的recv或send操作之后,都有可能调整缓冲区大小。
2. 阻塞式的send操作在写缓冲区剩余大小不足时,会一直等待。如果对方主动断开,阻塞的send会返回errno为104的复位标志。非阻塞的send会有多少空间就往里copy多少数据,没有空间则返回errno标志。
3. 通过recv()函数的MSG_PEEK标志可以大约知道读缓冲区有多少数据;通过ioctl(tcp_socket, SIOCOUTQ, &value)可以知道写缓冲区还有多少数据没发出去。
server端代码:
int main() { // ... // 建立listen端口的一些基本步骤 struct sockaddr_in client_addr; memset(&client_addr, 0, sizeof(client_addr)); socklen_t client_len = sizeof(client_addr); int new_client_sock = accept(listen_sock, (struct sockaddr *)&client_addr, &client_len); char client_ipv4_str[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &client_addr.sin_addr, client_ipv4_str, INET_ADDRSTRLEN); printf("Incoming connection from %s:%d.\n", client_ipv4_str, client_addr.sin_port); int val; int len = sizeof(val); getsockopt(new_client_sock, SOL_SOCKET, SO_RCVBUF, (void *)&val, (socklen_t*)&len); printf("size:%d\n", val); while (1) { sleep(1); } }
client:
int main() { // 。。。 // 建立连接的一些步骤 int val; int len = sizeof(val); getsockopt(clientfd, SOL_SOCKET, SO_SNDBUF, (void *)&val, (socklen_t*)&len); printf("size:%d\n", val); char buf[2626570]; while (1) { printf("here\n"); int size = send(clientfd, buf, 2626570, 0); printf("send size:%d\n", size); if (size < 0) printf("failed. %d, %d, $s\n", size, errno, strerror(errno)); getsockopt(clientfd, SOL_SOCKET, SO_SNDBUF, (void *)&val, (socklen_t*)&len); printf("size:%d\n", val); sleep(5); } while (1) { sleep(1); } }