一、创建服务端(Server)和客户端(Client)
初学时可以以对话框的形式创建两个工程分别定义为:Server和Client。
服务端的功能:用来进行数据的保存(保存形式可以是数据库;如果是简单测试用,则用CList或者CArray来模拟数据库的功能)以及处理客户端传送来的指令的处理,当然还需要人员的维护数据。
客户端的功能:则是用户的输入、删除、修改,浏览等功能,是用户体验的平台。
二、简单的“员工信息系统的服务端和客户端”
1.在服务器端:创建两个套接字(CSocket:阻塞的通讯类),一个用于监听(CListenSocket),一个用于保存数据以及对用户传来的指令进行处理(CClientSocket)。
a.监听处理时,重载虚函数OnAccept();
void CListenSocket::OnAccept(int nErrorCode)
{//每次当有客户端启动时,在堆内申请创建CClientSocket;
CClientSocket *pSock = new CClientSocket;
if (!Accept(*pSock))
delete pSock;
CSocket::OnAccept(nErrorCode);
}
b.然后在CClientSocket中重载OnReceive(),OnClose(),其中OnReceive接收客户端传来的指令和传进的数据,OnClose则是当其中一个或多个客户端关闭时释放(delete)new出来的内存(注意:在编码客户端程序时,应当将指令的类型和数据内容一起传过来,并先执行添加协议,但执行完整的添加协议需要两次接受数据(OnReceive),所以在客户端添加(Add)时,应当注意传的排序,先指令后数据,后面会讲到)
void CClientSocket::OnReceive(int nErrorCode)
{//接收客户端传来的指令和传进的数据
int nCmd = 0, nLen = 0;
if (Receive(&nCmd, sizeof(nCmd)) <= 0) //接受的指令类型;
return;
switch (nCmd)
{
case INF_ADD:
AddData(); //定义数据添加协议;
break;
case INF_BROW:
Browse(); //定义浏览数据协议;
break;
}
CSocket::OnReceive(nErrorCode);}
void CClientSocket::OnClose(int nErrorCode)
{//一个或多个客户端关闭时释放(delete)new出来的内存
delete this;
CSocket::OnClose(nErrorCode);}
c.定义协议的内容:
void CClientSocket::AddData()
{ //添加数据的协议处理;
SData data;
if (Receive(&data, sizeof(data)) <= 0)
return;
theApp.m_list.AddTail(data); //在CList的末尾添加元素;
}
void CClientSocket::Browse()
{ //浏览数据的协议处理,先发总数在逐步发送具体数据;
int nCount = theApp.m_list.GetCount();
Send(&nCount, sizeof(nCount));
POSITION pos = theApp.m_list.GetHeadPosition();
while (pos)
{
SData data = theApp.m_list.GetNext(pos);
Send(&data, sizeof(data));
}
}
1.在客户端:
BOOL CSK_nTCP_clientDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
m_sock.Create();
if (!m_sock.Connect(_T("169.254.216.64"), 8400))
{
CString str;
str.Format(_T("连接失败:无法连接服务器,请检查你的网络连接;\r\n%d"), GetLastError());
AfxMessageBox(str);
EndDialog(IDCANCEL);
return FALSE;
}
m_list.InsertColumn(0, _T("工号"), 0, 100);
m_list.InsertColumn(1, _T("姓名"), 0, 100);
m_list.InsertColumn(2, _T("工资"), 0, 100);
OnRefresh();
return TRUE;
}
void CSK_nTCP_clientDlg::OnPaint()
{
CDialogEx::OnPaint();}
void CSK_nTCP_clientDlg::OnBnClickedAdd()
{//先发送协议号编号再发送一条信息数据到服务器端;
int nCmd = INF_ADD;
m_sock.Send(&nCmd, sizeof(nCmd));
SData data = { (int)GetDlgItemInt(IDC_NUMB) };
GetDlgItemText(IDC_NAME, data.sName, sizeof(data.sName));
CString str;
GetDlgItemText(IDC_SALA, str);
data.fSala = (float)_wtof(str);
m_sock.Send(&data, sizeof(data));
OnRefresh();
}
void CSK_nTCP_clientDlg::OnRefresh()
{ // 发送完协议编号后,先接受数据总数再逐条接受每条具体数据;
int nCmd = INF_BROW;
m_sock.Send(&nCmd, sizeof(nCmd));
int nCount = 0, i = 0;
m_sock.Receive(&nCount, sizeof(nCount));
m_list.DeleteAllItems();
SData data;
CString str;
while (i < nCount)
{ //从服务端接受每条数据,并将内容插入到列表控件中显示;
m_sock.Receive(&data, sizeof(data));
str.Format(_T("%d"), data.nNumb);
m_list.InsertItem(i, str);
m_list.SetItemText(i, 1, data.sName);
str.Format(_T("%0.2f"), data.fSala);
m_list.SetItemText(i, 2, str);
i++;
}
}
(PS:注意以上不是完整的代码,仅提供参考的思路,路是自己走的,作为一名程序要有独立的思考能力!!)