您的位置:首页 > 理论基础 > 计算机网络

监听线程启动处理线程时需要注意的问题

2010-01-04 23:46 316 查看
        上次解决了文件传送的send与recv一致性问题后,以为大功告成了,可是原来更多隐藏得更深的问题还在后面。如果服务器接收一个线程的处理时还好,但是一有多个线程同时要求传送文件,那么问题就来了。试了两个线程同时发送文件,几乎每次都会有文件传送失败,代码怎么看都觉得没问题,从输出的调试信息中却发现两个不同的处理线程居然接收了同一个文件发送来的数据,还想着windwos的socket怎么就这么弱,居然数据一同时处理就接收出错了,后来无论怎么修改代码问题依旧,某天晚上准备睡觉时突然灵光一闪,想起了若干月前同样遇到过的一个错误,仔细一想错误肯定是出在这里了,这样轻松一改问题就解决了,唉,被一个同样的错误,只是换了个样就搞了那么久,看来人总是有重复历史的倾向。

看上去非常正常的代码,致命的错误就隐藏在里面了:

SOCKET sClient;

 while (server->brunning)
 {
  sClient = ::accept(server->sListen, (SOCKADDR*)&clientAddr, &nAddrLen);
  if (sClient == INVALID_SOCKET)
  {
   continue;
  }
          _beginthread(TcpFileTranServiceServer::handleIO, 0, sClient);
 }

void TcpFileTranServiceServer::handleIO(void* p)
{
    SOCKET sClient = *((SOCKET*)p);

 

以上的代码问题就出在如果有多个连接几乎同时发生时,处理线程都还没有启动就已经接收了新的连接,这样如果SOCKET是局部变量的话传给线程的值只是指向一个局部变量的指针,这样多个线程都接收到同一个SOCKET了,正确的做法应该这样:

SOCKET* sClient;

while (server->brunning)
 {
  sClient = new SOCKET;
  *sClient = ::accept(server->sListen, (SOCKADDR*)&clientAddr, &nAddrLen);
  if (*sClient == INVALID_SOCKET)
  {
   continue;
  }
          _beginthread(TcpFileTranServiceServer::handleIO, 0, sClient);

         // Sleep(1000); 当然如果不想new的话可以在这里睡一下,不过这就必然降低了效率,也不知道要睡多久才稳妥因此还是new一个SOCKET出来再把指针值传递给线程的参数,注意这里是值传递了
 }

 

void TcpFileTranServiceServer::handleIO(void* p)
{
    SOCKET sClient = *((SOCKET*)p);

 

        经过一轮的调试和不断修该bug,系统终于稍微稳定了,现在真的发现一个系统要稳定,特别是多线程下的网络系统,不只要有一个好的设计和编码,错误处理是非常重要的,因为线程和网络总不知道什么时候会出问题,出了问题后又怎样要它回到原来的状态,做好了错误处理系统才会可靠。另外系统最花时间的地方不是写代码阶段,而是调试和修改bug的阶段,所以前期做好错误处理和日志输出能够为之后的调试省下好多时间。

 

补:后来发现原来这样也可以,那就连new和delete也省了

SOCKET sClient;

while (server->brunning)
 {
  sClient = ::accept(server->sListen, (SOCKADDR*)&clientAddr, &nAddrLen);
  if (sClient == INVALID_SOCKET)
  {
   continue;
  }
          _beginthread(TcpFileTranServiceServer::handleIO, 0, (void*)sClient);

 }

 

void TcpFileTranServiceServer::handleIO(void* p)
{
    SOCKET sClient = (SOCKET)p;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息