SOCKET接收数据后加缓冲区出错,请高手指点!

artwl_cn 2010-05-10 09:47:23
开始没加缓冲区,没问题,主要代码如下:

void CChatRoomDlg::OnOK() //界面“监听”按钮事件
{
// TODO: Add extra validation here
sockaddr_in serveraddr;
serveraddr.sin_family=AF_INET;

unsigned char *pIP;
CString strIP;
DWORD dwIP;
m_serverip.GetAddress(dwIP);
pIP = (unsigned char*)&dwIP;
strIP.Format("%u.%u.%u.%u",*(pIP+3), *(pIP+2), *(pIP+1), *pIP);


serveraddr.sin_addr.S_un.S_addr=inet_addr(strIP);//m_serverIP;//inet_addr(m_serverIP);
UpdateData(TRUE);
serveraddr.sin_port=htons(m_port);
if(bind(m_server,(sockaddr*)&serveraddr,sizeof(serveraddr)))
{
MessageBox("绑定地址失败!");
return;
}
listen(m_server,50);
}

void CChatRoomDlg::HandleData() //接收到客户端数据后处理函数
{
sockaddr_in serveraddr;
char buffer[1024];
int len=sizeof(serveraddr);
int curlink=-1;
int num=-1;
for(int p=0;p<MAXNUM;p++)
{
num=recv(m_Clients[p],buffer,1024,0);
if(num!=-1)
{
CString sql,content;
for(int i=0;i<num;i++)
content+=buffer[i];
//把数据存入数据库
sql.Format("insert into Chat(ChatContent) values ('%s')",content);
DBOperation dboperation;
dboperation.InsertIntoDB(sql);
curlink=p;
break;
}
}
buffer[num]=0;
if(num==-1)
{
if(m_CurClient<MAXNUM)
{
m_Clients[m_CurClient]=accept(m_server,(struct sockaddr*)&serveraddr,&len);
m_CurClient++;
}
return;
}
//把信息发送给所有客户端
for(int j=0;j<m_CurClient;j++)
{
if(j!=curlink)
send(m_Clients[j],buffer,num,0);
}
}

BOOL CChatRoomDlg::PreTranslateMessage(MSG* pMsg)
{
// TODO: Add your specialized code here and/or call the base class
if(pMsg->message==20000)
{
HandleData();
return TRUE;
}
return CDialog::PreTranslateMessage(pMsg);
}


后考虑到如果较多用同时发送数据可能造成数据丢失(数据库操作速度小于数据发送速度),想加个缓冲区,我用的是多线程:线程一:把接收到的数据存入Vector<CString>对象中;线程二:把Vector<CString>对象中的数据存入数据库。
主要代码如下:

class CChatRoomDlg : public CDialog
{
...
public:
CString content;
friend UINT ThreadUpdateDB(LPVOID pParam);//线程一:把缓冲区数据存入数据库
friend UINT ThreadRecv(LPVOID pParam); //线程二:把发送来的数据存入缓冲区
HANDLE hEvent;
vector<CString> MessageArray; //缓冲区
DWORD dwIP;
void HandleData();
SOCKET m_server,m_client;
SOCKET m_Clients[MAXNUM];
int m_CurClient;
};

void CChatRoomDlg::OnOK() //界面“监听”按钮事件
{
//以上与上面一样
...
// 创建事件
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
// 事件置位
SetEvent(hEvent);
// 启动线程
AfxBeginThread(ThreadRecv, this);
AfxBeginThread(ThreadUpdateDB, this);

listen(m_server,50);
}

void CChatRoomDlg::HandleData()
{
//以上与上面一样
...
for(int p=0;p<MAXNUM;p++)
{
num=recv(m_Clients[p],buffer,1024,0);
if(num!=-1)
{
content="";
for(int i=0;i<num;i++)
content+=buffer[i];
curlink=p;
break;
}
}
//以下与上面一样
...
}

UINT ThreadRecv(LPVOID pParam) //把接收到的数据存入Vector<CString>对象中
{
CChatRoomDlg test;
// 等待事件置位
WaitForSingleObject(test.hEvent, INFINITE);
// 对共享资源进行写入操作
if(test.MessageArray.size()<1000&&test.content.GetLength()>0)
{
test.MessageArray.push_back(test.content);
}
// 处理完成后即将事件对象置位
SetEvent(test.hEvent);
return 0;
}

UINT ThreadUpdateDB(LPVOID pParam) //把Vector<CString>对象中的数据存入数据库。
{
// 等待事件置位
CString sql;
CChatRoomDlg test;
WaitForSingleObject(test.hEvent, INFINITE);
// 对共享资源进行写入操作
if(test.MessageArray.size()>0)
{
vector<CString> teststr;
sql.Format("insert into Chat(ChatContent) values ('%s')",test.MessageArray.at(0));
test.MessageArray.erase(0);
}
DBOperation dboperation;
dboperation.InsertIntoDB(sql);
// 处理完成后即将事件对象置位
SetEvent(test.hEvent);
return 0;
}

程序运行界面“监听”按钮事件后弹出“错误”,然后崩溃。
由于初学线程和MFC编程,有些地方不太懂,请高手指点,感激不尽!
...全文
88 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
songtao_01 2010-05-11
  • 打赏
  • 举报
回复
CChatRoomDlg* pTest = (CChatRoomDlg*)pParam;
wuhuwy 2010-05-11
  • 打赏
  • 举报
回复
多线程时确实容易出很多问题!
向立天 2010-05-11
  • 打赏
  • 举报
回复
你最好找个比较经典的局域网聊天程序来研究一下
cnzdgs 2010-05-11
  • 打赏
  • 举报
回复
线程中不能CChatRoomDlg test这样随便定义一个对象来使用,所有线程必须使用相同的对象,你在创建线程时已经把对象指针作为线程参数传给线程了,在各个线程中将pParam参数转换为CChatRoomDlg*类型,然后通过该指针来访问类成员。
Eleven 2010-05-10
  • 打赏
  • 举报
回复
你Debug打开call stack窗口,看看跑到哪个函数里以后抛出的异常。。。

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧