发送端与接收端一块实现.
1.
在StdAfx.h中包含头文件Afxsock.h,不用连接库文件Library: Use Ws2_32.lib.
CChatApp::InitInstance()加载套接字库
if(!AfxSocketInit())
{
AfxMessageBox("加载套接字库失败!");
return FALSE;
}//1.1
2.在CChatDlg增加一个成员变量
private:
SOCKET m_socket;
3.在CChatDlg中增加一个成员函数
BOOL CChatDlg::InitSocket()
{
m_socket=socket(AF_INET,SOCK_DGRAM,0);
if(INVALID_SOCKET==m_socket)
{
MessageBox("套接字创建失败!");
return FALSE;
}
SOCKADDR_IN addrSock;
addrSock.sin_family=AF_INET;
addrSock.sin_port=htons(6000);
addrSock.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
int retval;
retval=bind(m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR));
if(SOCKET_ERROR==retval)
{
closesocket(m_socket);
MessageBox("绑定失败!");
return FALSE;
}
return TRUE;
}
4.在BOOL CChatDlg::OnInitDialog()中调用InitSocket()进行初使化.
5.在接收数据时,recvfrom()是一个阻塞操作.所以要生成一个线程来完成这个操作,并且想给线程传进两个参数,一个是创建的socket,一个是对话框的句柄或是接收编辑框的句柄,这样就可以使接收到的数据传回给对话框或编辑框再进行处理.但先看看CreateThread()这个函数只提供给传递一个参数,但这个函数的第四个参数是一个指针,可以是一个变量的指针,也可是一个对象的指针.这样就可以给它传递一个结构体的指针.在这个结构体中包含了两个想传进的参数.
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
SIZE_T dwStackSize, // initial stack size
LPTHREAD_START_ROUTINE lpStartAddress, // thread function
LPVOID lpParameter, // thread argument
DWORD dwCreationFlags, // creation option
LPDWORD lpThreadId // thread identifier
);
所以在ChatDlg.h中定义一个结构体// ChatDlg.h : header file
struct RECVPARAM
{
SOCKET sock;
HWND hwnd;
};
在BOOL CChatDlg::OnInitDialog()中进行初使化.(就是InitSocket()下面)
RECVPARAM *pRecvParam=new RECVPARAM;
pRecvParam->sock=m_socket;
pRecvParam->hwnd=m_hWnd;
HANDLE hThread=CreateThread(NULL,0,RecvProc,(LPVOID)pRecvParam,0,NULL);
CloseHandle(hThread);
6.对线程操作函数进行编写.
先在CChatDlg中增加一个成员函数
public:
static DWORD WINAPI RecvProc(LPVOID lpParameter);//这个写可以体现面向对像,写可以写成全局函数.
再进行实现
DWORD WINAPI CChatDlg::RecvProc(LPVOID lpParameter)
{
SOCKET sock=((RECVPARAM*)lpParameter)->sock;
HWND hwnd=((RECVPARAM*)lpParameter)->hwnd;
delete lpParameter; //释放内存的操作
SOCKADDR_IN addrFrom;
int len=sizeof(SOCKADDR);
char recvBuf[200];
char tempBuf[300];
int retval;
while(TRUE)
{
retval=recvfrom(sock,recvBuf,200,0,(SOCKADDR*)&addrFrom,&len);
if(SOCKET_ERROR==retval)
break;
sprintf(tempBuf,"%s说: %s",inet_ntoa(addrFrom.sin_addr),recvBuf);
::PostMessage(hwnd,WM_RECVDATA,0,(LPARAM)tempBuf);//因为对话框句柄已经有了,可以通过发送消息给对话框传送数据. //消息先设为WM_RECVDATA.wParam设为0,数据可以通过lParam传递.
/**
BOOL PostMessage(
HWND hWnd, // handle to destination window
UINT Msg, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
*/
}
return 0;
}
7.在 ChatDlg.h : header file 中定义消息的值.就写在struct RECVPARAM上面
// CChatDlg dialog
#define WM_RECVDATA WM_USER+1
再在 ChatDlg.h : header file作一个[消息响应函数原型]的声明.
protected:
HICON m_hIcon;
// Generated message map functions
//{{AFX_MSG(CChatDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnBtnSend();
//}}AFX_MSG
afx_msg void OnRecvData(WPARAM wParam,LPARAM lParam);//这里作声明.注意:因为在发送消息的时候传递了一个参数.所以在声明消息响应函数时就要写上(WPARAM wParam,LPARAM lParam)
DECLARE_MESSAGE_MAP()
8.在ChatDlg.cpp进行消息映射.
BEGIN_MESSAGE_MAP(CChatDlg, CDialog)
//{{AFX_MSG_MAP(CChatDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BTN_SEND, OnBtnSend)
//}}AFX_MSG_MAP
ON_MESSAGE(WM_RECVDATA,OnRecvData)//这里作的映射.先前只是声明函数原型 .
END_MESSAGE_MAP()
9.进行消息响应函数的实现
void CChatDlg::OnRecvData(WPARAM wParam,LPARAM lParam)
{
CString str=(char*)lParam;
CString strTemp;
GetDlgItemText(IDC_EDIT_RECV,strTemp);
str+="/r/n";
str+=strTemp;
SetDlgItemText(IDC_EDIT_RECV,str);
}
/*******************以上是接收端,下面是发送端.**********/
void CChatDlg::OnBtnSend()
{
// TODO: Add your control notification handler code here
DWORD dwIP;
((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);
SOCKADDR_IN addrTo;
addrTo.sin_family=AF_INET;
addrTo.sin_port=htons(6000);
addrTo.sin_addr.S_un.S_addr=htonl(dwIP);
CString strSend;
GetDlgItemText(IDC_EDIT_SEND,strSend);
sendto(m_socket,strSend,strSend.GetLength()+1,0,
(SOCKADDR*)&addrTo,sizeof(SOCKADDR));
SetDlgItemText(IDC_EDIT_SEND,"");
}