一、首先为界面设置:
屏蔽一些控件,所以在你初始化时,添加代码如下:
BOOL CTCP客户程序Dlg::OnInitDialog() { CDialogEx::OnInitDialog(); // TODO: 在此添加额外的初始化代码 GetDlgItem(IDC_TEXT)->EnableWindow(FALSE); //将消息显示框,发送消息编辑框,发送按键禁用 GetDlgItem(IDC_SENDTEXT)->EnableWindow(FALSE); GetDlgItem(IDC_SEND)->EnableWindow(FALSE); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE }
在CTCP客户端程序Dlg::OnInitDialog()中包含:
s = ::socket(AF_INET, SOCK_STREAM, 0);
在class CTCP客户程序Dlg : public CDialogEx()中包含
SOCKET s; //定义套接字对象 sockaddr_in addr; //定义套接字地址结构变量
初始化如图所示:
1.connect按键:
void CTCP客户程序Dlg::OnBnClickedConnect() { // TODO: 在此添加控件通知处理程序代码 CString str, str1; int port; GetDlgItem(IDC_ADDR)->GetWindowText(str); GetDlgItem(IDC_PORT)->GetWindowText(str1); if ( str == "" || str1 == "" ) { MessageBox("服务器地址或者端口不能为NULL"); } else { port = atoi(str1.GetBuffer(1));//将端口字符串转换为数字 addr.sin_family = AF_INET; addr.sin_addr.S_un.S_addr = inet_addr(str.GetBuffer(1)); addr.sin_port = ntohs(port); GetDlgItem(IDC_TEXT)->SetWindowText("正在连接服务器....\r\n"); } if ( ::connect(s, (sockaddr*)&addr, sizeof(addr)) != SOCKET_ERROR ) { GetDlgItem(IDC_TEXT)->GetWindowText(str); str += "连接服务器成功!\r\n"; GetDlgItem(IDC_TEXT)->SetWindowText(str); GetDlgItem(IDC_SENDTEXT)->EnableWindow(true); GetDlgItem(IDC_SEND)->EnableWindow(true); GetDlgItem(IDC_ADDR)->EnableWindow(false); GetDlgItem(IDC_PORT)->EnableWindow(false); } else { GetDlgItem(IDC_TEXT)->GetWindowText(str); str += "连接服务器失败! 请重试\r\n"; GetDlgItem(IDC_TEXT)->SetWindowText(str); } }注:在vs2012中如果是unicode编码的话,在atoi(str1.GetBuffer(1))这会提示无法从LPCTSTR转化为const char*,最省事的办法是将编码方式选择为多字节
2.send按键
void CTCP客户程序Dlg::OnBnClickedSend() { // TODO: 在此添加控件通知处理程序代码 CString str, str1; GetDlgItem(IDC_SENDTEXT)->GetWindowText(str); if (str == "") { GetDlgItem(IDC_TEXT)->GetWindowTextA(str1); str1 += "\r\n"; str1 += "消息不能为空\r\n"; GetDlgItem(IDC_TEXT)->SetWindowText(str1); } else { ::send(s, str.GetBuffer(1), sizeof(str), 0); GetDlgItem(IDC_TEXT)->GetWindowTextA(str1); str1 += "\r\n"; str1 += str; GetDlgItem(IDC_TEXT)->SetWindowText(str1); } } LRESULT CTCP客户程序Dlg::OnSocket(WPARAM wParam, LPARAM lParam) { char cs[100] = {0}; if (lParam == FD_READ) { CString num = ""; recv(s, cs, 100, NULL); GetDlgItem(IDC_TEXT)->GetWindowText(num); num += "\r\n服务器说: "; num += (LPTSTR)cs; GetDlgItem(IDC_TEXT)->SetWindowText(num); } return true; }
这里采用异步套接字模式。
在BOOL CTCP客户程序Dlg::OnInitDialog()中初始化异步套接字模式
::WSAAsyncSelect(s, this->m_hWnd, WM_SOCKET, FD_READ);
将异步套接字处理的时间指定为读取时间,并将事件处理消息指定为WM_SOCKET,代码如下:
#define WM_SOCKET WM_USER + 100 class CTCP客户程序Dlg : public CDialogEx { afx_msg LRESULT OnSocket(WPARAM wParam, LPARAM lParam); }
BEGIN_MESSAGE_MAP(CTCP客户程序Dlg, CDialogEx) ON_MESSAGE(WM_SOCKET,OnSocket) END_MESSAGE_MAP()
LRESULT CTCP客户程序Dlg::OnSocket(WPARAM wParam, LPARAM lParam) { char cs[100] = {0}; if (lParam == FD_READ) { CString num = ""; recv(s, cs, 100, NULL); GetDlgItem(IDC_TEXT)->GetWindowText(num); num += "\r\n服务器说: "; num += (LPTSTR)cs; GetDlgItem(IDC_TEXT)->SetWindowText(num); } return true; }
SOCKET s, s1; sockaddr_in addr, addr1; int n;
BOOL CTCP服务器程序Dlg::OnInitDialog() { addr.sin_family = AF_INET; addr.sin_port = htons(75); addr.sin_addr.S_un.S_addr = INADDR_ANY; s = ::socket(AF_INET, SOCK_STREAM, 0); ::bind(s, (sockaddr*)&addr, sizeof(addr)); ::listen(s, 5); ::WSAAsyncSelect(s, this->m_hWnd, WM_SOCKET, FD_ACCEPT|FD_READ); GetDlgItem(IDC_TEXT)->EnableWindow(false); GetDlgItem(IDC_ADDR)->SetWindowText("服务器监听已经启动!"); }
#define WM_SOCKET WM_USER+10 class CTCP服务器程序Dlg : public CDialogEx { virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); afx_msg LRESULT OnSocket(WPARAM wParam, LPARAM lParam); DECLARE_MESSAGE_MAP() } ::WSAAsyncSelect(s, this->m_hWnd, WM_SOCKET, FD_ACCEPT|FD_READ);
ON_MESSAGE(WM_SOCKET, OnSocket)
LRESULT CTCP服务器程序Dlg::OnSocket(WPARAM wParam, LPARAM lParam) { CString str13; char cs[100] = {0}; switch (lParam) { case FD_ACCEPT: { int lenth = sizeof(addr1); s1 = ::accept(s, (sockaddr*)&addr1, &lenth); n = n + 1; str13.Format("有%d客户已经连接上了", n); GetDlgItem(IDC_TEXT)->SetWindowText(str13); str13 += ::inet_ntoa(addr1.sin_addr); str13 += "登录\r\n"; GetDlgItem(IDC_TEXT)->SetWindowText(str13); } break; case FD_READ: { CString num =""; ::recv(s1, cs, 100, 0); GetDlgItem(IDC_TEXT)->GetWindowText(num); num += "\r\n"; num += (LPCTSTR)::inet_ntoa(addr1.sin_addr); num += "对您说: "; num += (LPCTSTR)cs; GetDlgItem(IDC_TEXT)->SetWindowText(num); } break; } return true; }
void CTCP服务器程序Dlg::OnBnClickedSend() { // TODO: 在此添加控件通知处理程序代码 CString str = ""; GetDlgItem(IDC_SENDTEXT)->GetWindowText(str); if (str == "") { MessageBox("消息不能为空!"); } else { if (::send(s1, str.GetBuffer(1), sizeof(str), 0) != SOCKET_ERROR) { GetDlgItem(IDC_TEXT)->SetWindowText("消息已经发送到客户端!\r\n"); GetDlgItem(IDC_TEXT)->GetWindowText(str); str += "\r\n"; GetDlgItem(IDC_TEXT)->SetWindowText(str);; } else { GetDlgItem(IDC_TEXT)->SetWindowText("发送消息失败!\r\n"); } } }