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

《MFC网络通信》Part 2 简单TCP通信

2016-03-20 13:02 471 查看
《MFC网络通信》Part 2 简单TCP通信

一般TCP通信软件都分为服务器端和客户端。

TCP服务器端由一个侦听Socket和多个用于应答的Socket组成,每个应答Socket与客户端建立一对一的数据流通道。

客户端程序只包含一个链接Socket,它在成功连接服务器后与某一个应答Socket经行一对一的数据通信。

因此,我们需要创建两个程序,分别是服务器程序和客户端程序。分别命名为Server和Client。

第一步:创建Server服务器程序。

1、新建普通的MFC(exe)对话框程序,程序命名为Server,第二步中勾选Window Sockets。

2、创建工程完毕后,记得查看stdafx.h中的预编译头文件,检查是否包括:

#include <afxsock.h><span style="white-space:pre">	</span>//MFC socket extensions
3、查看类视图中的CServerApp类中的函数InitInstance函数是否自动生成以下代码:
BOOL CServerApp::InitInstance()
{
if (!AfxSocketInit())
{
AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
return FALSE;
}

// Standard initialization
// If you are not using these features and wish to reduce the size
//  of your final executable, you should remove from the following
//  the specific initialization routines you do not need.
……
4、在Server工程中创建一个CSocket类的派生类CListenSocket(Name中的1忽略掉):



5、同样的方法创建一个CSocket类的派生类CClientSocket。
6、在CServerApp类的头文件中添加一个指针链表类型的成员变量。

class CServerApp : public CWinApp
{
public:
CPtrList m_list;//公有成员变量存储与客户端通信的CClientSocket对象的地址

……


7、在创建的CListenSocket类中添加虚函数OnAccept,用于截获客户端的连接。

// CListenSocket member functions

#include "ClientSocket.h"
extern CServerApp theApp;

void CListenSocket::OnAccept(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class

//新建一个CClientSocket
CClientSocket *pSock = new CClientSocket;
if(Accept(*pSock))
theApp.m_list.AddTail(pSock);
else
delete pSock;

CSocket::OnAccept(nErrorCode);
}


8、在CClientSocket类中添加虚函数OnReceive,用于截获客户端发来的网络数据。

extern CServerApp theApp;

void CClientSocket::OnReceive(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
char s[2084];
int nLen = Receive(s,sizeof(s)-1);
if(nLen<0)
return ;
s[nLen] = 0;

CString szIP;
UINT nPort;
GetPeerName(szIP,nPort);
CString str;
str.Format("%d-%d对所有人说:\r\n%s\r\n",szIP,nPort,s);

CPtrList& list = theApp.m_list;
POSITION pos = list.GetHeadPosition();
while (pos)
{
//将一个客户端发来的聊天文字,群发给所有其他客户端
CClientSocket* pSock = (CClientSocket*)list.GetAt(pos);
//不对刚发出的聊天文字的客户端转发
if (pSock!=this)
pSock->Send(str,str.GetLength());
list.GetNext(pos);
}

CSocket::OnReceive(nErrorCode);
}


9、在CClientSocket类中添加虚函数OnClose,用于监测客户端是否断开了连接。

void CClientSocket::OnClose(int nErrorCode) //用于检测某个客户端是否断开了连接
{
// TODO: Add your specialized code here and/or call the base class
//将与客户端断开连接的CClientSocket对象地址从链表中移除
CPtrList &list= theApp.m_list;
POSITION pos =list.GetHeadPosition();
while (pos)
{
if (list.GetAt(pos)==this)
{
list.RemoveAt(pos);
break;
}
list.GetNext(pos);
}
//清理对象占用的堆空间
delete this;

CSocket::OnClose(nErrorCode);
}
10、主对话框类CServerDlg的头文件中,添加CListenSocket类型的成员变量m_sock。
#include "ListenSocket.h"

class CServerDlg : public CDialog
{
CListenSocket m_sock;//添加CListenScoket类型的成员变量
……
11、修改主对话框CServerDlg中的初始化函数,创建Socket并开始侦听。

BOOL CServerDlg::OnInitDialog()//初始化函数代码,创建socket并开始侦听
{
CDialog::OnInitDialog();

if(m_sock.Create(8118))
m_sock.Listen();
else
{
CString str;
str.Format("Socket Create Error.%d",GetLastError());
AfxMessageBox(str);
}

// Set the icon for this dialog.  The framework does this automatically
//  when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE);			// Set big icon
SetIcon(m_hIcon, FALSE);		// Set small icon

// TODO: Add extra initialization here

return TRUE;  // return TRUE  unless you set the focus to a control
}


12、编译运行即可,接下来创建客户端程序。

第二步:创建Client服务器程序。

1、创建Client工程,记得第二部勾选勾选Window Sockets。
2、主对话框中添加控件,如下图所示。



3、修改控件的属性列表。

控件类型		ID				CaptionStyle
Edit			IDC_HIST		多行、垂直滚动条、只读(去掉自动水平滚动条)
Edit			IDC_INPUT
Button			IDOK			发送(&S)
Button		 	IDCANCEL			关闭

4、创建CSocket的派生类CConnectSocket,过程同第一步:创建Server服务器程序——第4步相同。
5、在CConnectSocket类中添加虚函数OnReceive,用于截获服务器发来的网络数据。
void CConnectSocket::OnReceive(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
char s[2048];
int nLen = Receive(s,sizeof(s)-1);
if(nLen<=0)
return ;
s[nLen]=0;
CWnd* pWnd = AfxGetMainWnd();
CEdit* pEdit = (CEdit*)pWnd->GetDlgItem(IDC_HIST);
pEdit->SetSel(pEdit->GetWindowTextLength(),-1);
pEdit->ReplaceSel(s);

CSocket::OnReceive(nErrorCode);
}<span style="color:#3333ff;">
</span>
6、主对话框类头文件中添加一个CConnectSocket类型的成员变量。
#include "onnectSocket.h"//由于少写了个C
class CClientDlg : public CDialog
{
CConnectSocket m_sock;
7、修改主对话框中的初始化函数代码。
// CClientDlg message handlers

BOOL CClientDlg::OnInitDialog()
{
CDialog::OnInitDialog();

m_sock.Create();
if (!m_sock.Connect("192.168.1.46",8118))<span style="white-space:pre">	</span>//此处的IP地址记得写成自己电脑的IP
{
//连接服务器端运行的主机IP地址
CString str;
str.Format("连接失败:%d",GetLastError());
AfxMessageBox(str);
}
……
8、主对话框的类中,添加“发送(&S)”按钮的消息映射函数OnOK。
void CClientDlg::OnOK()
{
// TODO: Add extra validation here
CString szText;
GetDlgItemText(IDC_INPUT,szText);
if(m_sock.Send(szText,szText.GetLength())>0)
{
CEdit *pEdit = (CEdit*)GetDlgItem(IDC_HIST);
pEdit->SetSel(pEdit->GetWindowTextLength(),-1);
pEdit->ReplaceSel("\n你对所有人说:\r\n"+szText+"\r\n");
}
//CDialog::OnOK();
}


9、编译运行,首先要开启编译好的服务器端程序,再在一台或多台计算机开启客户端程序经行调试。

运行结果如下:



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: