Socket.Select()函数使用不当引发的问题(关于套接字在线程间传递是否可行的验证)
来源:互联网 发布:语义分割数据集 编辑:程序博客网 时间:2024/05/08 09:49
使用环境:VS2010 C#
做东西的时候碰到一个问题:
在后台中,创建了一个监听线程,用来监听是否有连接到监听地址的请求,如果有,则加入监听套接字集中;(这样的话,一个线程就可以接收N个套接字的信息)
创建了一个接收线程,对监听套接字集中的套接字进行消息接收,并将该消息显示出来;
其中,监听套接字集中有与服务器连接的套接字srvCommSock
出错状况:
类似下图所示
即,后台只收到了连接请求,但是却接收不到消息;
发送端则显示成功发送了消息,使用的是TCP/IP协议,所以是安全的;
但是消息跑哪儿了呢?
分析原因:
刚开始的时候毫无头绪,后来请教了下高手,说可能说线程A创建的套接字在线程B中可能访问不了(之后验证是可以的)
而且单步执行的时候,发现确实是有问题的。新加进来的套接字属性Socket.Connected为false(后来发现该属性不能作为套接字是否连接的依据,详细见文章Socket.Connected不能在调试时作为套接字是否连接的判断依据)
测试代码如下:
监听线程代码:
private void _lstnThreadProc() { //for check Console.WriteLine("_lstnThreadProc线程开始执行,监听其他用户的连接请求"); //开始监听 try { while (true) { Socket commSock = m_lstnSock.Accept(); //for test Console.WriteLine("接收到其他用户的连接请求\n"); //添加到监听套接字集中 m_readSet.Add(commSock); }//end of while }//end of try catch (SocketException e) { m_lstnSock.Close(); Console.WriteLine(e.Message); } }接收线程代码:
private void _threadProc() { //for check Console.WriteLine("_threadProc线程启动,准备接收数据信息\n"); byte[] recvBuf = new byte[1024]; while (true) { //获取监听套接字集 ArrayList readSet = m_readSet; int count = readSet.Count; //for test Console.WriteLine("_threadProc:监听集中有{0}个监听对象\n", count); if (count <= 0) { continue; } try { //阻塞等待 Socket.Select(readSet, null, null, -1); for (int nIter = 0; nIter < count; nIter++) { Socket sock = (Socket)readSet[nIter]; //表示有消息接收 int nRecv = sock.Receive(recvBuf); //正常处理 if (nRecv > 0) { string recvMsg = ASCIIEncoding.ASCII.GetString(recvBuf, 0, nRecv); Console.WriteLine("接收到的字节数为{0}消息如下\n{1}", nRecv, recvMsg); continue; } //其他用户与自己的连接断开 else { Console.WriteLine("与其他客户的连接断开\n"); m_readSet.Remove(sock); continue; }//end of else }//end of for }//end of try catch (SocketException e) { Console.WriteLine(e.Message); continue; } }//end of while(1) }
但是刚才在做实例的时候是可以执行的
正确执行的显示:
如果是示例可运行的话,那么原程序应该也没有问题呀
后来想起来,Socket.Select()方法的最后一个参数为-1时,表示阻塞执行的,而且初始化时,把与服务器通信的套接字srvCommSock加入到了套接字集中
这才分析得通:初始监听套接字集中有srvCommSock,而服务器没有消息发送过来,所以程序阻塞在了这里,后面的消息接收不到
Socket.Select()函数原型如下:
public static void Select(IList checkRead,IList checkWrite,IList checkError,int microSeconds)
Parameters
- checkRead
- Type: System.Collections.IList
An IList of Socket instances to check for readability.
- checkWrite
- Type: System.Collections.IList
An IList of Socket instances to check for writability.
- checkError
- Type: System.Collections.IList
An IList of Socket instances to check for errors.
- microSeconds
- Type: System.Int32
The time-out value, in microseconds. A -1 value indicates an infinite time-out.
问题解决:
将Socket.Select(readSet, null, null, -1);中的最后一个参数修改为0,即检测完如果没有消息就返回
需要解决的问题:
该示例虽然能正确执行,但是在_threadProc()函数中的while(true)循环会一直执行,所以会导致高CPU使用率。
合理的应该是监听线程_lstnThreadProc()函数中检测到连接之后,触发_threadProc()执行,这样的话就通过线程间的同步降低了CPU使用率
- Socket.Select()函数使用不当引发的问题(关于套接字在线程间传递是否可行的验证)
- socket中套接字传递给其他进程的问题
- break使用不当引发的一个“血案”
- 关于linux移植时Resetting CPU ...的问题(在我的系统中可行,已验证)
- 关于linux移植时Resetting CPU ...的问题(在我的系统中可行,已验证)
- socket套接字的使用
- 使用Socket套接字绑定函数bind的一个细节
- 验证JavaScript函数“按参数传递”特性引发的思考
- 线程函数参数引发的问题
- select函数是否阻塞与套接字的阻塞状态无关!!
- 关于iview表单验证select标签在使用v-for的时候验证一直不通过的问题
- 由Memcached使用不当而引发性能问题的两个经验总结
- 不当使用memset函数带来的麻烦问题
- socket编程中send函数引发的线程退出
- Socket.Connected不能在调试时作为套接字是否连接的判断依据
- 关于select函数的使用
- socket套接字使用的结构体
- Java套接字socket的使用
- ssh登陆之忽略known_hosts文件
- 习配置C,C++,GTK等开发环境
- TFS(Taobao File System) 简介
- VC6 中使用GDI+
- Win7 下的local settings
- Socket.Select()函数使用不当引发的问题(关于套接字在线程间传递是否可行的验证)
- SVN局域网服务器搭建
- 用QT产生报告的一种方案
- 编译OpenWrt - 索引
- 几种心态容易让装修不美满
- rails3项目解析——redis
- Terrocotta - 基于JVM的Java应用集群解决方案
- java 安全退出线程详解
- action可以直接获取html的变量内容(不用 request)