一、connect阻塞问题
在没有插网线时,会立即返回状态,插了网线会有阻塞75s,分析如下(再抄自:http://blog.sina.com.cn/s/blog_6592a07a0102v4sk.html)
1.采用select在学习嵌入式Linux网络编程中,很多同学都发现了一个问题,那就是调用connect函数时,如果服务端关闭,客户 端调用connect()函数时,发现阻塞在那里,而且利用ctrl+c信号去停止客户端程序时,需要等待一个较为长的时间才能响应了,这个时间如果大家 细心会发现,每次都是75秒的时间。那么有没有什么比较好的办法,可以以用户能接受的一个时间响应来停止掉一个正在connect连接的客户端那?比如我 们在做一个网络控制台的程序,用户需要随时可以停止掉任何一个网络服务连接,那么对于这样一个需要等待75秒时间才能反馈出服务状态的程序,用户是无法接 受的。
对于如何解决这个问题,我们可以分析下,要想完成用户在一个能接受的时间里迅速反馈出服务 端已经关闭的状态,那么我们的程序应该做到在一个规定的时间片内,可以捕获到用户发出的控制状态,然后处理用户的需求。那么要做到可以在规定的时间片内捕 获用户的控制状态,就必须禁止让我们的connect()函数阻塞75秒的情况发生,也就是说,要让connect()函数变为非阻塞状态才行。
好了,现在解决问题的关键就是如何把connect变为非阻塞状态了,我们知道,socket编程的操作对象是socket,而socket他又属于系统描述符类型,那么对于系统描述符,我们是怎么操作他变为非阻塞的那?是利用fcntl()函数或者ioctl()函数。
想到这里,好像问题应该已经解决了,但是我们调试发现,在服务端出现错误的时候,connect确实马上返回,但是,如果服务端正确那,connect还是马上返回,这样,我们无法判断connect函数是否成功了,那这个问题又该如何解决呢?
我们是否想到了一个select函数那,他具备监听文件描述符的功能,如果我们把之前的socket让select监听他是否可写,是不是问题也就解决了。
好了,那么我们总结下整个思路:
1.建立socket
2.将该socket设置为非阻塞模式
3.调用connect()
4.使用select()检查该socket描述符是否可写
5.根据select()返回的结果判断connect()结果
6.将socket设置为阻塞模式
对于第六步,为什么还要设置为阻塞模式
可能是为了后面的读、写考虑
unsigned long ul = 1;
ioctl(Socke_fd, FIONBIO, &ul);//设置为非阻塞
int error = -1, len;
len = sizeof(int);
struct timeval tm;
fd_set set;
ret = connect(Socke_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
if (ret < 0)
{
printf("socket connect faild,%d\n",ret);
tm.tv_sec = 2;
tm.tv_usec = 0;
FD_ZERO(&set);
FD_SET(Socke_fd, &set);
if(select(Socke_fd + 1, NULL, &set, NULL, &tm) > 0)
{
getsockopt(Socke_fd, SOL_SOCKET, SO_ERROR, &error, (socklen_t*)&len);
if(error == 0)
bret = true;
else
bret = false;
}
else
bret = false;
ul = 0;
ioctl(Socke_fd, FIONBIO, &ul);//设为阻塞
注意:以上的19至22行用来作为判断是否连接并不准确和是否插网线有联系(比如获取IP不上网),还需要完善,搞清楚再使用
二、服务端退出客户端也直接退出,或者是客户端退出服务端也退出的处理方法
Linux系统中当客户端断开连接后,服务端再次调用send接口时,底层会抛出SIGPIPE的信号,这个信号的缺省操作是进程直接退出。所以需要在代码中忽略这个信号,这里有两种方法:
方法一:
直接在服务端的send接口的参数进行设置:
ret = send(client_socket, buf, 10, MSG_NOSIGNAL);
客户端断开后返回的错误码:Broken pipe
附加描述:
函数原型:ssize_t send(int s, const void *buf, size_t len, ini flags);
flags参数:
0:此时同write
MSG_OOB:发送带外数据
MSG_DONTROUTE:告诉ip协议,目的主机在本地网络,不需要查找路由表
MSG_DONTWAIT:设置为非阻塞操作
MSG_NOSIGNAL:表示发送动作不被SIGPIPE信号中断
方法二:
include
…
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, 0);
sigaction的操作是检查或者修改与指定信号相关联的处理动作。
sigaction的用法参考:https://blog.csdn.net/weibo1230123/article/details/81411827
————————————————
版权声明:本文为CSDN博主「酸菜鱼的鱼」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u010299133/article/details/103637582