一个关于多线程网络编程的问题

twilight_oooo twilight_oooo 墨衍会员 · AI 创作全网分发 墨衍智能分发 通过墨衍一键同步至各平台 可同步平台 CSDN微信公众号微博知乎掘金百家号博客园抖音小红书 你的文章也可以这样分发 墨衍会员 ¥399起/年,写一次发全网 我也要 + 加入社区
我在编写一个多线程的聊天程序,在没有构建多线程之前,所有的功能运行良好,但是在重构成多线程之后,服务器端在接受数据时会出错,具体情况是这样的:

我在服务器端的CServerDoc的OnNewDocument()中启动端口的侦听以及多线程服务:
BOOL CServerDoc::OnNewDocument()
{
.....
clientList.RemoveAll(); //该全局链表用于存放向Server端发送数据的Client端对象,由各线程依次处理
m_pSocket = newCListeningSocket(this);
CThread (ReceThread;
ReceThread = new CReceiveThread(this);
CThreads *ReceThreads = new CThreads(ReceThread,5);
ReceThreas->Start(); //启动五个线程,当clientList中一有数据加入,就对其中的对象进行处理.

chPort = GetPrivateProfileInt(sConfigSection,"Port",1000,CONFIG_FILE);
if(m_pSocket->Create(chPort))
{
if(m_pSocket->Listen())
return TURE;
}
return FALSE;
}

当有用户通过客户端接入时,服务器端通过OnAccept消息响应函数来调用Doc类的ProcessPendingAccept()函数为该用户创建一个CClientSocket对象,用以从该用户的客户端接受数据或者将数据从服务器端发送给该用户,至此,进程都处于单线程状态:

void CServerDoc::ProcessPendingAccept()
{
CClientSocket* pSocket = new CClientSocket(this);
if(m_pSocket->Accept(*pSocket,(sockaddr*)&addr,&len))
{
pSocket->Init();
m_connectionList.AddTail(pSocket);//m_connectionList链表是Doc类的成员,用以存放连入服务器端的客户端(CClientSocket类)对象
}
else
delete pSocket;
}

当某个连入服务器的客户端有数据发送过来的时候,其相应的CClientSocket对象便启动事件使线程同步:

void CClientSocket::OnRecieve(int nErrorCode)
{
CSocket::OnReceive(nErrorCode);
clientList.AddTail(this); //将自己存入clientList链表中,等待某线程对其进行处理
if(clientList.GetCount()>0)
g_reclistStart.SetEvent(); // 开启事件,使等待中的线程启动
}

线程被解除等待状态之后会继续执行ClassProc()函数中接下去的程序,来处理排列在clientList中客户端Socket对象,接受其发过来的数据:

CRecieveThread::ClassProc()
{
while(1)
{
::WaitForSingleObject(g_rcvlistStart,INFINITE); //等待事件开启
m_cs.Lock();
if(clientList.GetCount()==0)
{
m_cs.Unlock();
cnotinue;
}
CClientSocket* pSocket = (CClientSocket*)clientList.RemoveTail(); //取出排在链表中的数据发送对象

if(clientList.GetCount()==0)
g_reclistStart.ResetEvent(); //链表为空时关闭事件
m_cs.Unlock();

do
{
CMsg* pMsg = ReadMsg(pSocket); //将对象传递的数据存入CMsg对象中(在此处出了问题)

if(pMsg->m_bClose)
{
m_cs.Lock();
m_pDoc->CloseSocket(pSocket);
m_cs.Unlock();
break;
}
}
while(!pSocket->m_pArchiveIn->IsBifferEmpty());

UpdateTable(pSocket);
UpdateClents();
}

return 1;
}

下面是ReadMsg()中的调用,其中代码很多,现只写出关键的调用:

CMsg* CRecieveThread::ReadMsg(CClientSocket* pSocket)
{
CMsg *msg = new CMsg();
......

TRY
{
pSocket->RecieveMsg(msg); 调用数据传递对象中的RecieveMsg()成员函数
......
}
......
return msg;
}

void CClientSocket::RecieveMsg(CMsg* pMsg)
{
pMsg->Serialize(*m_pArchiveIn);
}

void CMsg::Serialize(CArchive& ar)
{
if(ar.IsStoring())
{
ar<<(WORD)m_bClose;
ar<<m_strText;
}
else
{
CString stp;
WORD wd;
m_nameList.RemoveAll();
ar>>wd; //程序走到此处出错,似乎无法读出ar中的内容
m_bClose = (BOOL)wd;
ar>>m_strText;
......
}
m_msgList.Serialize(ar)
}

但是,我只要对程序稍加改动:

BOOL CServerDoc::OnNewDocument()
{
.....
clientList.RemoveAll();
m_pSocket = newCListeningSocket(this);
CThread (ReceThread;
ReceThread = new CReceiveThread(this);
CThreads *ReceThreads = new CThreads(ReceThread,5);

//ReceThreas->Start(); //注释掉该句

chPort = GetPrivateProfileInt(sConfigSection,"Port",1000,CONFIG_FILE);
if(m_pSocket->Create(chPort))
{
if(m_pSocket->Listen())
return TURE;
}
return FALSE;
}

void CClientSocket::OnReceive(int nErrorCode)
{
CSocket::(nErrorCode)
clientList.AddTail(this);
m_pCtd->ClassProc //当有数据传过来时直接用CReceiveThread类的指针调用ClassProc函数
// if(clientList.GetCount()>0)
// g_reclistStart.SetEvent();
}

CRecieveThread::ClassProc()
{
/* while(1)
{
::WaitForSingleObject(g_rcvlistStart,INFINITE); //等待事件开启
m_cs.Lock();
if(clientList.GetCount()==0)
{
m_cs.Unlock();
cnotinue;
}
*/
CClientSocket* pSocket = (CClientSocket*)clientList.RemoveTail(); //取出排在链表中的数据发送对象

if(clientList.GetCount()==0)
g_reclistStart.ResetEvent(); //链表为空时关闭事件
m_cs.Unlock();

do
{
CMsg* pMsg = ReadMsg(pSocket); //将对象传递的数据存入CMsg对象中(在此处出了问题)

if(pMsg->m_bClose)
{
m_cs.Lock();
m_pDoc->CloseSocket(pSocket);
m_cs.Unlock();
break;
}
}
while(!pSocket->m_pArchiveIn->IsBifferEmpty());

UpdateTable(pSocket);
UpdateClents();
// }

return 1;
}

这样的话就等于使用单线程,聊天程序便可以正常运行,ar中的内容也可以正常读出...我实在有点想不通为什么会发生这种错误,不知哪位高人可以看出其中的蹊跷,帮我指点一二
...全文

相关推荐

python网络编程之多线程同时接受和发送

**网络编程中的异常处理**:在进行网络编程时,需要注意错误处理。本文中的示例使用try-except语句来处理可能发生的OSError异常,这种异常通常与网络连接问题相关。5.

weixin_38633475

多线程编程实例适合网络编程人员

在IT行业中,多线程编程是一项至关重要的技术,特别是在网络编程领域。多线程使得一个程序可以同时执行多个任务,从而提高系统效率和响应速度。本文将深入探讨多线程编程实例及其在网络编程中的应用。

baiyun9070

网络编程、多线程聊天程序

在IT领域,网络编程和多线程是两个关键的概念,特别是在开发高效、实时的应用程序时。本项目"网络编程、多线程聊天程序"通过C++实现了一个聊天应用程序,旨在帮助开发者深入理解这两个主题。

nxbos

多线程和网络编程

然而,多线程也带来了线程安全问题,包括竞态条件、死锁和活锁,这些问题需要开发者谨慎处理。网络编程则涉及到在不同计算机间交换数据,它基于网络协议如TCP/IP,HTTP,FTP等。

YouNeverCanTell

Linux下基于socket的网络编程(包含多线程和Select机制)

在网络编程中,每个线程可以独立地处理一个客户端连接,提高服务器的并发能力。但需要注意的是,多线程编程需要考虑线程安全问题,如互斥锁、条件变量等同步机制的使用。

student毛
评论 10
收藏 已收藏
分享
返回顶部
twilight_oooo
网络编程 18,356 成员 64,161 内容