if(recv(sock,buff,sizeof(buff),0)==-1){
id=WSAGetLastError();}
可得到错误类型为10054,即WSAECONNRESET
ECONNRESET是linux环境网路编程形成的错误,错误码为104,
WSAECONNRESET是windows环境网路编程形成的错误,错误码为10054
二者形成的缘由都一样,分以下几种情况:
1接收端recv或则read,对端早已关掉联接,recv/read返回该错误
2对端重启联接,还未完善联接
3发送端早已断掉联接,并且调用send会触发这个错误
第二点第三点都可以通过判定返回值解决,第一点在一些杀死正常情况下也会触发该错误。
例如对端close(fd),接收端调用recv并没有返回0,而是-1,复印错误码为104或
10054,**按道理讲这些情况根据返回值为0处理是可以的linux recv函数,并且尽量将代码写的规范一些,
防止毋须要的错误。
为何close(fd)会造成接收端读到复位RST,也就是收到错误的104呢,
由于close(fd)只是将文件描述符关掉,并没有关掉tcp构建上去的联接,断掉联接须要四次握手,
如果发送端发送缓冲区有数据未发送完或则接受缓冲区有数据未读完美国linux主机,调用close(fd),这么联接并没有关掉,这样,接收端
收到的就是所谓的104或10054错误了。怎么避开这个错误呢,就须要我们判定发送端发送和接受操作
是否进行完,也就是判定缓冲区是否有数据,假如有数据须要等待数据处理完毕在关掉,否则会出现上述错误。
我有一个做法是通过调用shutdown(s,SHUT_WR);关掉发送端的写端,这样发送端不发送数据,之后调用close
此次会发送关掉联接的FIN标志,接收端接收到FIN,这么recv或则read返回的就是0.
intshutdown(intsockfd,inthow);
Sockfd是须要关掉的socket的描述符。参数how准许为shutdown操作选择以下几种方法:
SHUT_RD:关掉联接的读端。也就是该套接字不再接受数据,任何当前在套接字接受缓冲区的数据将被遗弃。
进程将不能对该套接字发出任何读操作。
对TCP套接字该调用以后接受到的任何数据将被确认之后无声的遗弃掉。
SHUT_WR:关掉联接的写端,进程不能在对此套接字发出写操作
SHUT_RDWR:相当于调用shutdown两次:首先是以SHUT_RD,之后以SHUT_WR
下边摘用网上的一段话来说明两者的区别:
close-----关掉本进程的socketid,但链接还是开着的,用这个socketid的其它进程能够用这个链接,能读或写这个socketid
shutdown–则破坏了socket链接linux recv函数,读的时侯可能侦探到EOF结束符,写的时侯可能会收到一个SIGPIPE讯号,这个讯号可能直至
socketbuffer被填充了才收到。
close(sockfd);使用close终止一个联接,但它只是降低描述符的参考数,并不直接关掉联接,只有当描述符的参考数为0时才关掉联接。
但是shutdown只是处理联接关掉,并不能回收描述符,所以最终还是要调用close(fd)能够回收描述符,在所有描述符引用次数为0时发送FIN消息给对端。
出了采取shutdown的方法,还可以通过设置socket属性,调用close时,测量在socket完成缓冲区读写后,才关掉联接。
struct linger {
int l_onoff; /* 0 = off, nozero = on */
int l_linger; /* linger time */
};
有下述三种情况:
1、设置l_onoff为0,则该选项关掉,l_linger的值被忽视,等于内核缺省情况,close调用会立刻返回给调用者,假如可能将会传输任何未发送的数据;
2、设置l_onoff为非0,l_linger为0,则套插口关掉时TCP夭亡联接,TCP将遗弃保留在套插口发送缓冲区中的任何数据并发送一个RST给对方,而不是一般的四分组中止序列,这防止了TIME_WAIT状态;
3、设置l_onoff为非0,l_linger为非0linux系统装win7,当套插口关掉时内核将拖延一段时间(由l_linger决定)。假如套插口缓冲区中仍残留数据,进程将处于睡眠状态,直到(a)所有数据发送完且被对方确认,然后进行正常的中止序列(描述字访问计数为0)或(b)延后时间到。
下边是代码:
int z;
int s;
struct linger so_linger;
so_linger.l_onoff = 1
so_linger.l_linger = 30;
z = setsockopt(s,SOL_SOCKET,SO_LINGER,&so_linger,
sizeof so_linger);
if ( z )
perror("setsockopt(2)");
close(s);
到目前为止,我认为比较好的主动关掉方法是:
关掉端:
1确保发送缓存区没有数据未发送,调用shutdown(fd,SHUTWR);
2倘若能接收到数据,继续接受,直至接收到对方的FIN,也就是
read返回0或则-1
3假如接收到关掉讯号,这么调用close正常关掉。
当client,调用read(socketfd,buffer,n)时,返回0的情况:
1、server端调用了close(soketfd)函数
2、server调用了close(fd,SHUT_WR),关掉server端的写联接,半关掉