刚开学找了个工作,要做嵌入式方面的,用的是winCE平台,因为之前没有用过,指导我们的大虾就让我们写一个聊天器,一个是客户端的,一个是服务端,要求使用时,有服务器开启服务,然后客户端便可以连接到服务端,连接成功后双方便可以通信聊天等,我费了一周时间才基本做了出来,给各位参考参考,里面共涉及到以下知识:
VC++语言,(这个我之前可是不会的,一直用C,区别太大了。)
多线程,(创建线程,接收数据时用,我不会用非阻塞式socket,只好创建新的线程,这个要好好看看。)
socket,(socket的创建,连接,接收,发送,断开等,挺复杂的。)
下面就给出程序,供大家参考,因为前段时间重装了系统,没有vs2008,只能上传程序,没有截图,凑活看吧。
// chat_clientDlg.cpp : 实现文件
// Edit by lineter
// QQ: 542375845
#include "stdafx.h"
#include "chat_client.h"
#include "chat_clientDlg.h"
DWORD ReciveThread(PVOID pArg);
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// Cchat_clientDlg 对话框
Cchat_clientDlg::Cchat_clientDlg(CWnd* pParent /*=NULL*/)
: CDialog(Cchat_clientDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void Cchat_clientDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_EDIT1, idcEdit1);
}
BEGIN_MESSAGE_MAP(Cchat_clientDlg, CDialog)
#if defined(_DEVICE_RESOLUTION_AWARE) && !defined(WIN32_PLATFORM_WFSP)
ON_WM_SIZE()
#endif
//}}AFX_MSG_MAP
ON_BN_CLICKED(IDC_BUTTON1, &Cchat_clientDlg::OnBnClickedButton1)
ON_BN_CLICKED(IDC_BUTTON2, &Cchat_clientDlg::OnBnClickedButton2)
ON_BN_CLICKED(IDC_BUTTON3, &Cchat_clientDlg::OnBnClickedButton3)
ON_EN_CHANGE(IDC_EDIT2, &Cchat_clientDlg::OnEnChangeEdit2)
ON_BN_CLICKED(IDC_BUTTON4, &Cchat_clientDlg::OnBnClickedButton4)
END_MESSAGE_MAP()
// 接收线程
DWORD ReciveThread(PVOID pArg)
{
// TODO: 在此添加控件通知处理程序代码
Cchat_clientDlg *p=(Cchat_clientDlg *)pArg;
CString csContent; // 接收到的数据
int recv_no=0;
char cRecvBuf[100];
while(1)
{
// 清空字符串
memset(cRecvBuf,0,sizeof(cRecvBuf));
// 接收数据
recv_no=recv(p->sockClient,cRecvBuf,100,0);
// 处理接收到的数据
csContent.Empty();
csContent.Append((CString)cRecvBuf);
csContent.Insert(0,CString("Server:"));
csContent.Append(CString("\r\n"));
// 调用类中显示数据的函数
p->DispRecive(csContent);
Sleep(1000);
}
return 0;
}
// 显示接收到的内容
void Cchat_clientDlg::DispRecive(CString csContent)
{
CString csAllcontent;
// 得到文本框内容,并将数据加上顶端显示
GetDlgItemText(IDC_EDIT1,csAllcontent);
SetDlgItemText(IDC_EDIT1,csContent+csAllcontent);
}
// Cchat_clientDlg 消息处理程序
BOOL Cchat_clientDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// 显示默认服务器ip
CString csContent;
csContent="";
csContent.Append(CString("192.168.3.73"));
SetDlgItemText(IDC_EDIT3,csContent);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
#if defined(_DEVICE_RESOLUTION_AWARE) && !defined(WIN32_PLATFORM_WFSP)
void Cchat_clientDlg::OnSize(UINT /*nType*/, int /*cx*/, int /*cy*/)
{
if (AfxIsDRAEnabled())
{
DRA::RelayoutDialog(
AfxGetResourceHandle(),
this->m_hWnd,
DRA::GetDisplayMode() != DRA::Portrait ?
MAKEINTRESOURCE(IDD_CHAT_CLIENT_DIALOG_WIDE) :
MAKEINTRESOURCE(IDD_CHAT_CLIENT_DIALOG));
}
}
#endif
void Cchat_clientDlg::OnEnChangeEditIp()
{
// TODO: 如果该控件是 RICHEDIT 控件,则它将不会
// 发送该通知,除非重写 CDialog::OnInitDialog()
// 函数并调用 CRichEditCtrl().SetEventMask(),
// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
// TODO: 在此添加控件通知处理程序代码
}
void Cchat_clientDlg::OnEnChangeEditPort()
{
// TODO: 如果该控件是 RICHEDIT 控件,则它将不会
// 发送该通知,除非重写 CDialog::OnInitDialog()
// 函数并调用 CRichEditCtrl().SetEventMask(),
// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
// TODO: 在此添加控件通知处理程序代码
}
// 发送内容
void Cchat_clientDlg::OnBnClickedButton1()
{
CString csContent;
char cRecvBuf[100];
CString csAllcontent;
char cAllcontent[500];
csContent = "";
memset(cRecvBuf,0,sizeof(cRecvBuf));
memset(cAllcontent,0,sizeof(cAllcontent));
// 得到输入内容并发送
GetDlgItemText(IDC_EDIT2,csContent);
WCharToMByte(csContent,(LPSTR)cRecvBuf,sizeof(cRecvBuf)/sizeof(cRecvBuf[0]));
send(sockClient,cRecvBuf,strlen(cRecvBuf)+1,0);
// 将输入内容处理后显示
csContent.Insert(0,CString("Client:"));
csContent.Append(CString("\r\n"));
DispRecive(csContent);
}
// 关闭连接
void Cchat_clientDlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
DWORD ExitCode; // 线程退出码
// 得到线程退出码
GetExitCodeThread(handle1,&ExitCode);
// 通过线程退出码结束线程
TerminateThread(handle1,ExitCode);
// 关闭线程句柄
CloseHandle(handle1);
handle1=NULL;
// 关闭socket
closesocket(sockClient);
WSACleanup();
// 显示断开信息
CString csCancel;
csCancel.Append(CString("Disconnected !"));
SetDlgItemText(IDC_EDIT2,csCancel);
// 更改控件属性
GetDlgItem(IDC_BUTTON1)-> EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON2)-> EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON4)-> EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON3)-> EnableWindow(TRUE);
}
// 建立连接
void Cchat_clientDlg::OnBnClickedButton3()
{
// TODO: 在此添加控件通知处理程序代码
CString csContent; // 输入框中内容,即IP地址(CString 类型)
char cIP[100]; // 输入框中内容,即IP地址(char 类型)
csContent.Empty(); // 清空原始内容
memset(cIP,0,sizeof(cIP)); // 清空字符串
// 得到输入框中内容并转换为char型
GetDlgItemText(IDC_EDIT3,csContent);
WCharToMByte(csContent,(LPSTR)cIP,sizeof(cIP)/sizeof(cIP[0]));
// 创建socket,客服端
wVersionRequested = MAKEWORD( 1, 1 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
{
AfxMessageBox(CString("WSAStartup error"),0,0);
return;
}
if ( LOBYTE( wsaData.wVersion ) != 1 ||
HIBYTE( wsaData.wVersion ) != 1 )
{
AfxMessageBox(CString("LOBYTE error"),0,0);
WSACleanup( );
AfxMessageBox(CString("LOBYTE OK error"),0,0);
return;
}
sockClient=socket(AF_INET,SOCK_STREAM,0); // 客户端socket
// 通过ip地址和端口和服务器连接
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=inet_addr(cIP);
//addrSrv.sin_addr.S_un.S_addr=inet_addr("192.168.3.73");
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(1000);
connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
// 显示连接成功信息
CString csOk;
csOk.Append(CString("Connected !"));
SetDlgItemText(IDC_EDIT2,csOk);
// 修改控件属性
GetDlgItem(IDC_BUTTON1)-> EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON2)-> EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON4)-> EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON3)-> EnableWindow(FALSE);
// 创建接收数据进程
handle1=CreateThread(NULL,0,ReciveThread,this,0,NULL);
}
void Cchat_clientDlg::OnEnChangeEdit2()
{
// TODO: 如果该控件是 RICHEDIT 控件,则它将不会
// 发送该通知,除非重写 CDialog::OnInitDialog()
// 函数并调用 CRichEditCtrl().SetEventMask(),
// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
// TODO: 在此添加控件通知处理程序代码
}
// CString转char 函数
BOOL Cchat_clientDlg::WCharToMByte(LPCWSTR lpcwszStr, LPSTR lpszStr, DWORD dwSize)
{
DWORD dwMinSize;
dwMinSize = WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,NULL,0,NULL,FALSE);
if(dwSize+1 < dwMinSize)
{
return FALSE;
}
WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,lpszStr,dwSize,NULL,FALSE);
return TRUE;
}
// 按键接收函数。警告:按下后将卡死至接收到数据
void Cchat_clientDlg::OnBnClickedButton4()
{
// TODO: 在此添加控件通知处理程序代码
CString csContent;
CString csAllcontent;
int recv_no=0;
char cRecvBuf[100];
// 通过socket接收数据,阻塞式
recv_no=recv(sockClient,cRecvBuf,100,0);
// 将接收到的数据处理后放入输入框顶端
csContent.Empty();
csContent.Append((CString)cRecvBuf);
csContent.Insert(0,CString("Server:"));
csContent.Append(CString("\r\n"));
DispRecive(csContent);
}
共有两个文本编辑框,4个按键,对应的头文件也有相应更改如下
// chat_clientDlg.h : 头文件
//
#pragma once
#include <Winsock2.h>
#pragma comment(lib, "Ws2.lib")
#include <stdio.h>
#include "afxwin.h"
// Cchat_clientDlg 对话框
class Cchat_clientDlg : public CDialog
{
// 构造
public:
Cchat_clientDlg(CWnd* pParent = NULL); // 标准构造函数
// 对话框数据
enum { IDD = IDD_CHAT_CLIENT_DIALOG };
WORD wVersionRequested;
WSADATA wsaData;
int err;
SOCKET sockClient,sockSrv;
BOOL WCharToMByte(LPCWSTR lpcwszStr, LPSTR lpszStr, DWORD dwSize);
DWORD WINAPI revThread(LPVOID lpParameter);
void DispRecive(CString csContent); //显示接收到的数据
HANDLE handle1; // 进程的句柄
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
#if defined(_DEVICE_RESOLUTION_AWARE) && !defined(WIN32_PLATFORM_WFSP)
afx_msg void OnSize(UINT /*nType*/, int /*cx*/, int /*cy*/);
#endif
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnEnChangeEdit1();
afx_msg void OnEnChangeEditIp();
afx_msg void OnEnChangeEditPort();
afx_msg void OnBnClickedButton1();
afx_msg void OnBnClickedButton2();
afx_msg void OnBnClickedButton3();
afx_msg void OnEnChangeEdit2();
afx_msg void OnBnClickedButton4();
CEdit idcEdit1;
};
以上是客户端,还有服务端,和客户端很像,但也有一些不同。
// chat_serverDlg.cpp : 实现文件 // #include "stdafx.h" #include "chat_server.h" #include "chat_serverDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #endif DWORD ReciveThread(PVOID pArg); // CString转char 函数 BOOL Cchat_serverDlg::WCharToMByte(LPCWSTR lpcwszStr, LPSTR lpszStr, DWORD dwSize) { DWORD dwMinSize; dwMinSize = WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,NULL,0,NULL,FALSE); if(dwSize+1 < dwMinSize) { return FALSE; } WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,lpszStr,dwSize,NULL,FALSE); return TRUE; } // 接收线程 DWORD ReciveThread(PVOID pArg) { // TODO: 在此添加控件通知处理程序代码 Cchat_serverDlg *p=(Cchat_serverDlg *)pArg; int recv_no=0; char cRecvBuf[100]; CString csContent; SOCKADDR_IN addrClient; int len=sizeof(SOCKADDR); memset(cRecvBuf,0,sizeof(cRecvBuf)); p->sockConn=accept(p->sockSrv,(SOCKADDR*)&addrClient,&len); p->DispInfo(CString("one connected.")); p->EnableSend(TRUE); while(1) { recv(p->sockConn,cRecvBuf,100,0); csContent.Empty(); csContent.Append((CString)cRecvBuf); csContent.Insert(0,CString("Server:")); csContent.Append(CString("\r\n")); if(cRecvBuf[0]!=0) { p->DispRecive(csContent); } else { p->EnableSend(FALSE); closesocket(p->sockConn); p->DispInfo(CString("one disconnected.")); p->sockConn=accept(p->sockSrv,(SOCKADDR*)&addrClient,&len); p->DispInfo(CString("one connected.")); p->EnableSend(TRUE); } } return 0; } // 是否使能发送框 void Cchat_serverDlg::EnableSend(BOOL enable_send) { if(enable_send) { GetDlgItem(IDC_BUTTON1)-> EnableWindow(TRUE); } else { GetDlgItem(IDC_BUTTON1)-> EnableWindow(FALSE); } } // 将数据显示在文本框之上 void Cchat_serverDlg::DispRecive(CString csContent) { CString csAllcontent; GetDlgItemText(IDC_EDIT1,csAllcontent); SetDlgItemText(IDC_EDIT1,csContent+csAllcontent); } // 显示提示信息 void Cchat_serverDlg::DispInfo(CString csContent) { SetDlgItemText(IDC_EDIT2,csContent); } Cchat_serverDlg::Cchat_serverDlg(CWnd* pParent /*=NULL*/) : CDialog(Cchat_serverDlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void Cchat_serverDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(Cchat_serverDlg, CDialog) #if defined(_DEVICE_RESOLUTION_AWARE) && !defined(WIN32_PLATFORM_WFSP) ON_WM_SIZE() #endif //}}AFX_MSG_MAP ON_BN_CLICKED(IDC_BUTTON3, &Cchat_serverDlg::OnBnClickedButton3) ON_BN_CLICKED(IDC_BUTTON2, &Cchat_serverDlg::OnBnClickedButton2) ON_BN_CLICKED(IDC_BUTTON1, &Cchat_serverDlg::OnBnClickedButton1) END_MESSAGE_MAP() // Cchat_serverDlg 消息处理程序 BOOL Cchat_serverDlg::OnInitDialog() { CDialog::OnInitDialog(); // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } #if defined(_DEVICE_RESOLUTION_AWARE) && !defined(WIN32_PLATFORM_WFSP) void Cchat_serverDlg::OnSize(UINT /*nType*/, int /*cx*/, int /*cy*/) { if (AfxIsDRAEnabled()) { DRA::RelayoutDialog( AfxGetResourceHandle(), this->m_hWnd, DRA::GetDisplayMode() != DRA::Portrait ? MAKEINTRESOURCE(IDD_CHAT_SERVER_DIALOG_WIDE) : MAKEINTRESOURCE(IDD_CHAT_SERVER_DIALOG)); } } #endif void Cchat_serverDlg::OnBnClickedButton3() { // TODO: 在此添加控件通知处理程序代码 WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 1, 1 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { return; } if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) { WSACleanup( ); return; } sockSrv=socket(AF_INET,SOCK_STREAM,0); SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY); addrSrv.sin_family=AF_INET; addrSrv.sin_port=htons(1000); bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)); listen(sockSrv,5); handle1=CreateThread(NULL,0,ReciveThread,this,0,NULL); GetDlgItem(IDC_BUTTON1)-> EnableWindow(FALSE); GetDlgItem(IDC_BUTTON2)-> EnableWindow(TRUE); GetDlgItem(IDC_BUTTON3)-> EnableWindow(FALSE); DispInfo(CString("Server start!")); } void Cchat_serverDlg::OnBnClickedButton2() { // TODO: 在此添加控件通知处理程序代码 DWORD ExitCode; // 线程退出码 // 得到线程退出码 GetExitCodeThread(handle1,&ExitCode); // 通过线程退出码结束线程 TerminateThread(handle1,ExitCode); // 关闭线程句柄 CloseHandle(handle1); handle1=NULL; // 关闭socket closesocket(sockSrv); WSACleanup(); // 更改控件属性 GetDlgItem(IDC_BUTTON1)-> EnableWindow(FALSE); GetDlgItem(IDC_BUTTON2)-> EnableWindow(FALSE); GetDlgItem(IDC_BUTTON3)-> EnableWindow(TRUE); // 显示断开信息 DispInfo(CString("Server closed!")); } void Cchat_serverDlg::OnBnClickedButton1() { CString csContent; char cRecvBuf[100]; CString csAllcontent; char cAllcontent[500];
// chat_serverDlg.h : 头文件 // #pragma once #include <Winsock2.h> #pragma comment(lib, "Ws2.lib") #include <stdio.h> #include "afxwin.h" // Cchat_serverDlg 对话框 class Cchat_serverDlg : public CDialog { // 构造 public: Cchat_serverDlg(CWnd* pParent = NULL); // 标准构造函数 // 对话框数据 enum { IDD = IDD_CHAT_SERVER_DIALOG }; /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ SOCKET sockSrv; SOCKET sockConn; void DispRecive(CString csContent); //显示接收到的数据 HANDLE handle1; // 进程的句柄 BOOL WCharToMByte(LPCWSTR lpcwszStr, LPSTR lpszStr, DWORD dwSize); void Cchat_serverDlg::DispInfo(CString csContent); // 显示信息 void EnableSend(BOOL enable_send); // 是否使能发送键 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: HICON m_hIcon; // 生成的消息映射函数 virtual BOOL OnInitDialog(); #if defined(_DEVICE_RESOLUTION_AWARE) && !defined(WIN32_PLATFORM_WFSP) afx_msg void OnSize(UINT /*nType*/, int /*cx*/, int /*cy*/); #endif DECLARE_MESSAGE_MAP() public: afx_msg void OnBnClickedButton3(); afx_msg void OnBnClickedButton2(); afx_msg void OnBnClickedButton1(); };
int len=sizeof(SOCKADDR);csContent = "";memset(cRecvBuf,0,sizeof(cRecvBuf));memset(cAllcontent,0,sizeof(cAllcontent));// 得到输入内容并发送GetDlgItemText(IDC_EDIT2,csContent);WCharToMByte(csContent,(LPSTR)cRecvBuf,sizeof(cRecvBuf)/sizeof(cRecvBuf[0]));send(sockConn,cRecvBuf,strlen(cRecvBuf)+1,0);// 将输入内容处理后显示csContent.Insert(0,CString("Client:"));csContent.Append(CString("\r\n"));DispRecive(csContent);}
以上就是全部代码,有需要源文件的可以直接留言,告诉我邮箱,我会尽快发送给各位。