linux TCP 如何解决阻塞?

qlz37238 2011-10-21 11:27:00
代码1

while(1){
size=recv(s,buff,1024,0);
write(1,buff,size);
}



代码2

while(1){
size=recv(s,buff,1024,0);
sprintf(buffer,"content %s,bytes %d",buff,size);
write(1,buffer,strlen(buffer));
}


在上面的代码中服务器端使用recv函数来接收客户端send函数发送的数据。
如果使用代码1。服务器端能正常接收输出。如果是客户端退出了。那么服务器端也是正常的。一直等待。
如果是使用代码2。服务端也能正常接收并且输出。但是如果客户端一量退出的话。那么服务器端就不正常了。服务器端就会反复无限循环输出。除非是自己中断。
这种是怎么回事呢?是因为阻塞的原因吗?如果想要解决这种问题的话。那应该怎么办呀?

服务器端

#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
void process_conn(int);
int main(void)
{
int s;
struct sockaddr_in server,client;
int err;
s=socket(AF_INET,SOCK_STREAM,0);
server.sin_family=AF_INET;
server.sin_port=htons(8889);
server.sin_addr.s_addr=inet_addr("192.168.1.2");
err=bind(s,(struct sockaddr *)&server,sizeof(struct sockaddr));
if(err<0){
perror("bind");
return -1;
}
err=listen(s,2);
if(err<0){
perror("listen");
return -1;
}
while(1){
int sc;
socklen_t len=sizeof(struct sockaddr);
sc=accept(s,(struct sockaddr *)&client,&len);
pid_t pid;
pid=fork();
if(pid==0){
close(s);
process_conn(sc);
}else
close(sc);
}
return 0;
}

void process_conn(int s)
{
ssize_t size=0;
char buff[1024],buffer[1024];
while(1){
size=recv(s,buff,1024,0);
write(1,buff,size);
}

/*
while(1){
size=recv(s,buff,1024,0);
sprintf(buffer,"%s,%d",buff,size);
write(1,buffer,strlen(buffer));
}
*/
}


...全文
457 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
qlz37238 2011-10-22
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 qq120848369 的回复:]
楼主连recv返回值都不会,洗洗睡撒.
[/Quote]


使用了recv的返回值。

if(size<1)//size==0,size==-1
return;
加上了这么一句过后。
等客户端退出过后linux 奇卡无比。。 只有关了服务器端过后就才能恢复正常。如果把这一句去掉。就没问题。这个就是我郁闷的地方。。。不知道是不是因为我的linux 的原因。
shenyan008 2011-10-22
  • 打赏
  • 举报
回复
问题原因不清楚,但是 buffer 有可能溢出。
qq120848369 2011-10-22
  • 打赏
  • 举报
回复
楼主连recv返回值都不会,洗洗睡撒.
lovestefanie 2011-10-22
  • 打赏
  • 举报
回复
fcntl

int flag = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flga | O_NONBLACK);

ioctl

int nIO = 1;
ioctl(sockfd, FIONBIO, &nIO);
lovestefanie 2011-10-22
  • 打赏
  • 举报
回复
如果只有一个sock的话
可以使用阻塞式I/O,采用alarm进行超时控制
如果sock多的话,可以采用select多路复用

也可以直接使用非阻塞式的I/O,用fcntl()设置成O_NONBLOCK或者用ioctl()设置成FIONBIO
dfsdfsdfwedfwef 2011-10-22
  • 打赏
  • 举报
回复
recv的返回值 >0 表示收到正常数据,=0,对端关闭,<0 发生错误,,客户端关闭后,recv 返回0,这时需要关闭s,,楼主的代码,在客户端关闭了socket的情况下,继续recv write,是会发送错误的 ,这时就不是阻塞了

while(1){ size=recv(s,buff,1024,0); write(1,buff,size); }

while(1){ size=recv(s,buff,1024,0); sprintf(buffer,"content %s,bytes %d",buff,size); write(1,buffer,strlen(buffer)); }

代码1,recv错误后 ,size= -1,write写了一个负数长度到缓冲区,,write也会返回错误,,
代码2,buffer的长度>0,关闭套接字的情况下写也会返回错误

代码1,代码2,在对端关闭后,子进程没有退出,都会一直循环,,楼主所说的 1阻塞 ,,2一直输出,是不是因为 1的buff 根本就没数据,2里面的sprintf放数据进去了,看到输出了呢

vilnies 2011-10-22
  • 打赏
  • 举报
回复
要先判断一下recv的返回值size,返回值是-1或者0的时候你后面的代码就有问题了
qlz37238 2011-10-22
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 shenyan008 的回复:]
问题原因不清楚,但是 buffer 有可能溢出。
[/Quote]

漏出不会呀。
我只是做的小测试。buffer是1024字节。而我只是发的几个字节的东西
qlz37238 2011-10-22
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 qq551780977 的回复:]

引用 13 楼 qlz37238 的回复:
引用 12 楼 liang_cheng_jie 的回复:
认真看书吧,这些问题本本书都有讲


我有认真看书。而是我的这本书里面的确没有讲这一些东西。

换一本网络编程的专著看看.....
[/Quote]

看的也是一本网络编程的 叫《linux网络编程》
qlz37238 2011-10-22
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 qq120848369 的回复:]

跟楼主说了错误,楼主自己还看不懂,服了。
[/Quote]

汗。我没说不懂啊。 。

白天有事上不了网。晚上才能上网。所以现在来结贴给分。

两次都麻烦你。。



只不过。相当感谢你啊。

呵呵。



还有就是感谢其它回答的各位。

结贴给分啦。!!



qq120848369 2011-10-22
  • 打赏
  • 举报
回复
跟楼主说了错误,楼主自己还看不懂,服了。
QQ551780977 2011-10-22
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 qlz37238 的回复:]
引用 12 楼 liang_cheng_jie 的回复:
认真看书吧,这些问题本本书都有讲


我有认真看书。而是我的这本书里面的确没有讲这一些东西。
[/Quote]
换一本网络编程的专著看看.....
秦剑 2011-10-22
  • 打赏
  • 举报
回复
http://linux.die.net/man/2/recv

Return Value

These calls return the number of bytes received, or -1 if an error occurred. The return value will be 0 when the peer has performed an orderly shutdown.

为什么都光说楼主不说问题。
qlz37238 2011-10-22
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 liang_cheng_jie 的回复:]
认真看书吧,这些问题本本书都有讲
[/Quote]

我有认真看书。而是我的这本书里面的确没有讲这一些东西。
liang_cheng_jie 2011-10-22
  • 打赏
  • 举报
回复
认真看书吧,这些问题本本书都有讲
qq120848369 2011-10-22
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 qq120848369 的回复:]
你的代码是有问题的,子进程的process_conn发现recv<=0,调用了return只是退出process_conn函数而已,子进程没有exit继续跑,结果跑到了while循环,结果accept的s在子进程里已经被close了,而你没检查accept的返回值,于是继续往下跑,再fork,然后各种调用全部错误,无限fork。
[/Quote]

#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
void process_conn(int);
int main(void)
{
int s;
struct sockaddr_in server,client;
int err;
s=socket(AF_INET,SOCK_STREAM,0);
server.sin_family=AF_INET;
server.sin_port=htons(8889);
server.sin_addr.s_addr=inet_addr("192.168.1.2");
err=bind(s,(struct sockaddr *)&server,sizeof(struct sockaddr));
if(err<0){
perror("bind");
return -1;
}
err=listen(s,2);
if(err<0){
perror("listen");
return -1;
}
while(1){
int sc;
socklen_t len=sizeof(struct sockaddr);
sc=accept(s,(struct sockaddr *)&client,&len);
pid_t pid;
pid=fork();
if(pid==0)
{
close(s);
process_conn(sc);
exit(0); //子进程要主动退出,否则子进程会继续跑,而且子进程里关闭了s,跑到accpet就 悲剧的无限错误下去,无限的子进程将被创建.
}else
{
close(sc);
}
}
return 0;
}

void process_conn(int s)
{
ssize_t size=0;
char buff[1024],buffer[1024];
while(1){
size=recv(s,buff,1024,0);
if(size<=0){return;}
write(1,buff,size);
}
}

qq120848369 2011-10-22
  • 打赏
  • 举报
回复
你的代码是有问题的,子进程的process_conn发现recv<=0,调用了return只是退出process_conn函数而已,子进程没有exit继续跑,结果跑到了while循环,结果accept的s在子进程里已经被close了,而你没检查accept的返回值,于是继续往下跑,再fork,然后各种调用全部错误,无限fork。

Gloveing 2011-10-21
  • 打赏
  • 举报
回复
设置超时:
ioctlsocket WSAIoctl

69,369

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧