MFC下的网络编程(3)CS结构信息转发器的实现
服务器端
CListenSocket m_listenSocket; //监听套接字
点击启动服务按键
//创建监听套接字,激发FD_ACCEPT事件,默认端口5088
BOOL bFlag=m_listenSocket.Create(5088,SOCK_STREAM,FD_ACCEPT);
m_listenSocket.Listen(1);
在OnAccept()函数中
//侦听到连接请求,调用Accept函数
CNewSocket* pSocket = new CNewSocket();
if(Accept(*pSocket)) //接受连接
{
pSocket->AsyncSelect(FD_READ); //有读事件的时候,Socket中的OnReceive事件就会触发
m_pSocket=pSocket; //记录当前通信Socket
}
else
delete pSocket;
CAsyncSocket::OnAccept(nErrorCode);
在OnReceive()函数中
m_nLength=Receive(m_szBuffer,sizeof(m_szBuffer),0);
// 直接转发消息
AsyncSelect(FD_WRITE); //触发OnSend函数
CAsyncSocket::OnReceive(nErrorCode);
在OnSend()函数中,发送接收到的数据
char m_sendBuffer[4096]; //消息缓冲区
memcpy(m_sendBuffer,"服务器转发:",24);
strncat(m_sendBuffer,m_szBuffer,m_nLength);
Send(m_sendBuffer,sizeof(m_sendBuffer)); //发送数据
AsyncSelect(FD_READ); //触发OnReceive函数
CAsyncSocket::OnSend(nErrorCode);
客户端
CClientSocket m_clientSocket;
点击连接按键,执行OnConnect函数
m_clientSocket.ShutDown(2);
m_clientSocket.m_hSocket=INVALID_SOCKET;
m_clientSocket.m_bConnected=FALSE;
CAddrDlg m_Dlg;
m_szPort=5088;//默认端口5088
if (m_Dlg.DoModal()==IDOK && !m_Dlg.m_Addr.IsEmpty())
//填写IP地址,点击确认键
{
memcpy(m_szServerAdr,m_Dlg.m_Addr,sizeof(m_szServerAdr));
//建立计时器,每1秒尝试连接一次,直到连上或TryCount>10
SetTimer(1,1000,NULL);
TryCount=0;
}
在定时器处理函数中
BOOL bFlag=m_clientSocket.Create(0,SOCK_STREAM,FD_CONNECT);
//创建套接字
m_clientSocket.Connect(m_szServerAdr,m_szPort);
//连接服务器
TryCount++; //连接次数加1
if (TryCount >=10 || m_clientSocket.m_bConnected) //如果已经连接或连接超时
{
KillTimer(1); //关闭定时器
if (TryCount >=10) //连接超时
{
AfxMessageBox("连接失败!");
GetDlgItem(IDC_CONNECT)->EnableWindow(true);
}
return;
}
至此连接结束,接下来就是发送数据,填好发送的信息后,点击发送按键,执行OnSend函数
if (m_clientSocket.m_bConnected) //先检查是否已经连接
{
//获取用户数据的待发送信息
m_clientSocket.m_nLength=m_MsgS.GetWindowText(m_clientSocket.m_szBuffer, sizeof(m_clientSocket.m_szBuffer));
//触发Socket的OnSend函数
m_clientSocket.AsyncSelect(FD_WRITE);
}
在CClientSocket和CTransClientDlg这两个类中都有OnConnect、OnSend函数,前面说的都是CTransClientDlg这个类中的函数。下面用到的是CClientSocket中的
AsyncSelect括号内的参数是诸如FD_CONNECT、FD_WRITE、FD_READ这些常量
。
AsyncSelect(FD_READ)投递一个“读“的事件,准备接收,如果有读事件的时候,那么OnReceive事件就会触发,
如果传入FD_WRITE就投了一个“写”事件,那么当发送数据的时候,你的OnSend事件就会触发。可以用|来表示需要监听多个事件。
在触发的OnSend函数中发送数据
Send(m_szBuffer,m_nLength,0);//发送数据
m_nLength=0;
memset(m_szBuffer,0,sizeof(m_szBuffer));//清除缓冲区数据
//继续提请一个"读"的网络事件,如果有读事件的时候,那么OnReceive事件就会触发
AsyncSelect(FD_READ);
CAsyncSocket::OnSend(nErrorCode);
因为在之前调用了AsyncSelect(FD_READ),当收到服务器信息后,就会执行OnReceive函数
m_nLength=Receive(m_szBuffer,sizeof(m_szBuffer),0); //接收数据
pDlg->m_MsgR.InsertString(0,m_szBuffer);//列表框添加接收的数据
memset(m_szBuffer,0,sizeof(m_szBuffer));//清除缓冲区数据