C语言socket清空缓存,C语言socket send()数据缓存有关问题

本文通过一个C语言的socket编程实例,探讨了Nagle算法如何影响数据发送,并解释了TCP_NODELAY选项的作用。在某些情况下,即使设置了TCP_NODELAY,如果send()发送数据过快,系统仍可能进行数据缓存。为避免数据打包,建议在send()后加入usleep()延迟,确保数据按预期发送。同时,文章还提供了客户端和服务端的代码示例来展示不同设置下的行为差异。
摘要由CSDN通过智能技术生成

C语言socket send()数据缓存问题

send()函数默认情况下会使用Nagle算法,Nagle算法通过将未确认的数据存入缓冲区直到积攒到一定数量一起发送的方法,来减少主机发送零碎小数据包的数目。所以如果send()函数发送数据过快的话,该算法会将一些数据打包后统一发出去。如果不了接这种情况,接收端采会遇到看似很奇怪的问题,比如成功recv()的次数与成功send()的次数不相等,在这中情况下,接收端可以通过recv()的返回值是否为0来判断发送端是否发送完毕。

通过setsockopt()的TCP_NODELAY选项来禁用Nagle算法。但经试验这种方法似乎不总是有效,不过对于相同数量的send(),设置了TCP_NODELAY选项后recv()成功的次数要比设置之前多出几倍。这是不是说明设置了TCP_NODELAY后,系统会进最大的努力不去缓存,但是如果send的实在太快的话,还是会缓存的。

因此,如果你不希望send()的数据被本地缓存到一定数量之后再发送,而是send()多少次就发送多少次,稳妥的方式还是每次send之后调用一下usleep()函数,给系统一个反应的时间。

下面的例子演示了send()调用的快慢对数据是否打包的影响,注释掉server里的usleep(1000),会导致数据打包发送。

TCP_NODELAY是唯一使用IPPROTO_TCP层的选项,宏TCP_NODELAY的头文件是linux/tcp.h或者netinet/tcp.h。

因为不知到send()数据缓存的问题,我调试一天的程序,我的五一劳动节啊!!

server.c:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

//#include

int main(){

int socksv, sockcl;

struct sockaddr_in server_addr;

struct sockaddr_in client_addr;

int sin_size;

if((socksv = socket(AF_INET, SOCK_STREAM, 0)) == -1){

printf("sever socket fail\n");

return -1;

}

memset(&server_addr, 0, sizeof(struct sockaddr_in));

server_addr.sin_family = AF_INET;

server_addr.sin_port = htons(6001);

server_addr.sin_addr.s_addr = INADDR_ANY;

int r = 1;

setsockopt(socksv, SOL_SOCKET, SO_REUSEADDR, &r, sizeof(int));

int t = 1;

if(-1 == setsockopt(socksv, IPPROTO_TCP, TCP_NODELAY, &t, sizeof(int))){

printf("setsockopt fail\n");

return -1;

}

if(bind(socksv, (struct sockaddr *)&server_addr,

sizeof(struct sockaddr)) == -1){

printf("server bind fail\n");

return -1;

}

if(listen(socksv, 5) == -1){

printf("server listen fail\n");

return -1;

}

while(1){

sin_size = sizeof(struct sockaddr_in);

if((sockcl = accept(socksv, (struct sockaddr *)&client_addr, &sin_size)) == -1){

printf("server accept fail\n");

continue;

}

int times = 1024;

int allbytes = 0;

int i;

for(i = 0; i < times; i++){

char buf[] = "#this is a message from ptypeServer";

int sendbytes;

if((sendbytes = send(sockcl, buf, strlen(buf), 0)) == -1){

printf("server send fail\n");

}

usleep(1000);

allbytes += sendbytes;

}

printf("have send %d packages to client, allbytes=%d\n", times, allbytes);

close(sockcl);

}

}

client.c:

#include

#include

#include

#include

#include

#include

#include

#include

#include

int main(){

int socksv;

char buf[1024 * 1024];

if((socksv = socket(AF_INET, SOCK_STREAM, 0)) == -1){

printf("socket fail\n");

return -1;

}

struct sockaddr_in server_addr;

memset(&server_addr, 0, sizeof(struct sockaddr_in));

server_addr.sin_family = AF_INET;

server_addr.sin_port = htons(6001);

server_addr.sin_addr.s_addr = inet_addr("192.168.1.100");

if(connect(socksv, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1){

printf("connect fail\n");

return -1;

}

int times = 0;

int allbytes = 0;

int numbytes = 1;

while(numbytes != 0){

times++;

if((numbytes = recv(socksv, buf, sizeof(buf), 0)) == -1){

printf("recv fail\n");

return -1;

}

//buf[numbytes] = '\0';

//printf("numbytes=%d buf=[%s]\n", numbytes, buf);

allbytes += numbytes;

}

printf("server is closed, have recv %d packages from server, "

"allbytes=%d\n", times - 1, allbytes);

}

参阅:http://baike.baidu.com/link?url=-QgA0U7iv5tno-qnorYKDMNazOeOdcGk-pKIVFcOy-n6vhoITKdzlCg1VZYjqJ1DnOlpaaA54E7HrqQX6Bc_e_

在 C 语言中实现 Socket 长连接的方法如下: 1. 创建 Socket 使用 socket() 函数创建一个套接字,指定协议族、套接字类型和协议。例如: ``` int sockfd = socket(AF_INET, SOCK_STREAM, 0); ``` 2. 绑定 Socket 使用 bind() 函数将套接字与本地 IP 地址和端口绑定。例如: ``` struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_port = htons(8888); int ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)); ``` 3. 监听 Socket 使用 listen() 函数将套接字设置为监听状态,等待客户端连接。例如: ``` int ret = listen(sockfd, 5); ``` 4. 接受客户端连接 使用 accept() 函数接受客户端连接,返回一个新的套接字描述符用于与客户端进行通信。例如: ``` struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(client_addr); int clientfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_addr_len); ``` 5. 进行数据通信 使用 send() 和 recv() 函数进行数据通信。例如: ``` char buffer[1024]; int ret = recv(clientfd, buffer, sizeof(buffer), 0); ret = send(clientfd, buffer, strlen(buffer), 0); ``` 6. 关闭连接 使用 close() 函数关闭套接字。例如: ``` close(clientfd); close(sockfd); ``` 在长连接中,客户端和服务器之间的连接不会立即关闭,而是保持连接状态,等待下一次通信。需要注意的是,在长连接中,应该及时处理客户端发来的数据,避免出现阻塞或缓存溢出等问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值