一、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设置为阻塞模式

对于第六步,为什么还要设置为阻塞模式
可能是为了后面的读、写考虑

  1. unsigned long ul = 1;
  2. ioctl(Socke_fd, FIONBIO, &ul);//设置为非阻塞
  3. int error = -1, len;
  4. len = sizeof(int);
  5. struct timeval tm;
  6. fd_set set;
  7. ret = connect(Socke_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
  8. if (ret < 0)
  9. {
  10. printf("socket connect faild,%d\n",ret);
  11. tm.tv_sec = 2;
  12. tm.tv_usec = 0;
  13. FD_ZERO(&set);
  14. FD_SET(Socke_fd, &set);
  15. if(select(Socke_fd + 1, NULL, &set, NULL, &tm) > 0)
  16. {
  17. getsockopt(Socke_fd, SOL_SOCKET, SO_ERROR, &error, (socklen_t*)&len);
  18. if(error == 0)
  19. bret = true;
  20. else
  21. bret = false;
  22. }
  23. else
  24. bret = false;
  25. ul = 0;
  26. 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