我是用vs2013编写的。
一,建客户端项目
打开vs,新建对话框项目,勾选套接字
点击完成。
接下来,修改对话框界面
增加两个EDIT控件,上面的ID是IDC_HIST,多行,只读,无水平滚动条 ,有垂直滚动条。下面的ID是IDC_INPUT,其他不做改变。增加一个按钮控件,ID是IDC_BUTTON1,文字为连接。OK按钮文字修改为发送(&s)
增加一个类,可以点击项目菜单添加类ConnectSocket,基类是CSocket。
代码实现:
在ClientDlg.h文件添加:
#include "ConnectSocket.h"
CConnectSocket m_sock;
在 BOOL CClientDlg::OnInitDialog()函数下添加如下代码:
CDialogEx::OnInitDialog();
m_sock.Create();
if (!m_sock.Connect(_T("192.168.0.8"), 8118))//此处的IP地址记得写成自己电脑的IP
{
//连接服务器端运行的主机IP地址
/*CString str;
str.Format(_T("连接失败:%d"), GetLastError());
AfxMessageBox(str);*/
LPVOID lpMsgBuf;
FormatMessage
(
FORMAT_MESSAGE_ALLOCATE_BUFFER | //返回一个已分配的内存
FORMAT_MESSAGE_FROM_SYSTEM | //系统消息
FORMAT_MESSAGE_IGNORE_INSERTS, //无视插入信息
NULL,
GetLastError(),
0, //默认语言
(LPTSTR)&lpMsgBuf, //错误信息指针
0,
NULL
);
MessageBox((LPCTSTR)lpMsgBuf, NULL, MB_OK | MB_ICONINFORMATION);
LocalFree(lpMsgBuf);//释放内存
}
else
{
CString sockStr;
UINT port;
CString str;
m_sock.GetSockName(sockStr,port);
str.Format(_T("客户端%s:%u"), sockStr, port);
SetWindowText(str); //设置对话框的标题
}
..........
为发送按钮添加代码:
// TODO: 在此添加控件通知处理程序代码
CString szText;
int len;
GetDlgItemText(IDC_INPUT, szText);
len = szText.GetLength()*2;
if (m_sock.Send(szText, len) == len)
{
CEdit *pEdit = (CEdit*)GetDlgItem(IDC_HIST);
pEdit->SetSel(pEdit->GetWindowTextLength(), -1);
pEdit->ReplaceSel(_T("\n你对所有人说:\r\n") + szText + "\r\n");
}
else
{
MessageBox(_T("发送失败"), _T("警告"), MB_OK);
}
// CDialogEx::OnOK();
在对话框双击连接按钮,为连接按钮添加代码:
void CClientDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
// m_sock.Create();
if (!m_sock.Connect(_T("192.168.0.8"), 8118))//此处的IP地址记得写成自己电脑的IP
{
//连接服务器端运行的主机IP地址
CString str;
//str.Format(_T("连接失败:%d"), GetLastError());
LPVOID lpMsgBuf;
FormatMessage
(
FORMAT_MESSAGE_ALLOCATE_BUFFER | //返回一个已分配的内存
FORMAT_MESSAGE_FROM_SYSTEM | //系统消息
FORMAT_MESSAGE_IGNORE_INSERTS, //无视插入信息
NULL,
GetLastError(),
0, //默认语言
(LPTSTR)&lpMsgBuf, //错误信息指针
0,
NULL
);
MessageBox((LPCTSTR)lpMsgBuf, NULL, MB_OK | MB_ICONINFORMATION);
LocalFree(lpMsgBuf);//释放内存
//AfxMessageBox(str);
}
}
ConnectSocket.h文件添加:
virtual void OnReceive(int nErrorCode);
ConnectSocket.cpp添加:
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)-2);
if (nLen <= 0)
return;
s[nLen] = 0;
s[nLen+1] = 0;
CWnd* pWnd = AfxGetMainWnd();
CEdit* pEdit = (CEdit*)pWnd->GetDlgItem(IDC_HIST);
pEdit->SetSel(pEdit->GetWindowTextLength(), -1);
CString cstr((wchar_t*)s);
pEdit->ReplaceSel(cstr);
CSocket::OnReceive(nErrorCode);
为确定、取消按钮添加代码:
void CServerDlg::OnBnClickedCancel()
{
// TODO: 在此添加控件通知处理程序代码
m_sock.Close();
CDialogEx::OnCancel();
}
客户端代码完成。
服务器端:新建Server对话框项目,勾选套接字。
对话框界面,
添加一个EDIT控件,ID是IDC_TEXT1,多行,只读,无水平滚动条,有垂直滚动条
添加ClientSocket类,基类Socket。声明函数,
virtual void OnReceive(int nErrorCode);
virtual void OnClose(int nErrorCode);
代码实现:
// ClientSocket.cpp : 实现文件
//
#include "stdafx.h"
#include "Server.h"
#include "ClientSocket.h"
#include "resource.h"
extern CServerApp theApp;
// CClientSocket
CClientSocket::CClientSocket()
{
}
CClientSocket::~CClientSocket()
{
}
// CClientSocket 成员函数
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;
nLen= Receive(s, sizeof(s)-2);
if (nLen<0)
return;
s[nLen] = 0;
s[nLen+1] = 0;
CString szIP;
UINT nPort;
GetPeerName(szIP, nPort);
CString str;
str.Format(_T("%s-%u对所有人说:\r\n%s\r\n"), szIP, nPort, s);
CEdit *pEdit = (CEdit*)theApp.m_pMainWnd->GetDlgItem(IDC_TEXT1);
pEdit->SetSel(pEdit->GetWindowTextLength(), -1);
pEdit->ReplaceSel(str + "\r\n");
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()*2);
list.GetNext(pos);
}
CSocket::OnReceive(nErrorCode);
}
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);
}
添加ListenSocket,基类Socket,在头文件 声明函数: virtual void OnAccept(int nErrorCode);
#pragma once
// CListenSocket 命令目标
class CListenSocket : public CSocket
{
public:
CListenSocket();
virtual ~CListenSocket();
virtual void OnAccept(int nErrorCode);
};
代码实现:
// CListenSocket 成员函数
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);
}
在server.cpp添加代码:
if (!AfxSocketInit())
{
AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
return FALSE;
}
在ServerDlg.h添加:
#include "ListenSocket.h"
class CServerDlg : public CDialogEx
{
// 构造
public:
CServerDlg(CWnd* pParent = NULL); // 标准构造函数
CListenSocket m_sock;//添加CListenScoket类型的成员变量
..........
在ServerDlg.cpp 添加代码:
BOOL CServerDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
if (m_sock.Create(8118))
m_sock.Listen();
else
{
CString str;
str.Format(_T("Socket Create Error.%d"), GetLastError());
AfxMessageBox(str);
}
// 将“关于...”菜单项添加到系统菜单中
为取消按钮添加代码:
void CServerDlg::OnBnClickedCancel()
{
// TODO: 在此添加控件通知处理程序代码
m_sock.Close();
CDialogEx::OnCancel();
}
到此代码差不多了,字符串长度乘2是因为宽字符实际占两个字节。
可以多客户端和服务器连接通信。
参考:《MFC网络通信》Part 2 简单TCP通信_梁的博客-CSDN博客_mfc tcp通信 https://blog.csdn.net/sinat_24206709/article/details/50936127
有一点改进:MFC EDIT控件最多容纳30000个字符, socket 网络通信连续接收程序代码_ywqb95的博客-CSDN博客