监听线程启动处理线程时需要注意的问题
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;
看上去非常正常的代码,致命的错误就隐藏在里面了:
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;
相关文章推荐
- 字典转模型需要注意的问题,以及第三方框架来处理字典转模型
- 【转】字典转模型需要注意的问题,以及第三方框架来处理字典转模型
- android 启动线程注意的问题
- Oracle 11.2 单实例连接ASM时需要注意的事项以及问题处理
- Linux上复制tomcat启动需要注意的问题
- MySQL处理空值时你需要注意的两个问题
- 过滤器实现登录拦截需要注意的问题(AJAX请求的处理)
- .NET中静态变量的使用需要注意线程安全问题
- 利用反射调用方法时,处理ref,out参数需要注意的问题(转)
- web应用程序开发注意私自启动线程的问题
- MySQL处理空值时你需要注意的两个问题
- 时间处理工具类,和使用字符串或者日期处理需要注意的问题
- linux 处理设备号需要注意的问题
- CURL多线程处理需要注意问题
- NPOI导出Excel2007-xlsx格式文件,用于web时需要注意的问题-XSSFWorkbook处理问题
- 远程线程需要注意的问题
- 分数求和:一道很有意思的题,而且最后的返回值的处理问题也需要注意
- 使用异常处理语句需要注意的几个问题
- linux 处理设备号需要注意的问题
- 大数据处理前所需要注意的问题