简单聊天程序分析

 

 

发送端与接收端一块实现.

 

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,"");
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值