您的位置:首页 > 理论基础 > 计算机网络

使用套接字函数设计网络聊天室

2014-04-29 17:08 441 查看
在18.3.2节中笔者介绍了常用的套接字函数,接下来将利用这些套接字函数设计一个网络聊天室程序。程序由两个实例组成,第1个实例为服务器端,负责接收用户的连接请求,并转发用户信息。第2个实例为客户端,负责连接服务器并发送信息。

服务器端程序设计步骤如下:

ch1806实例位置:mr\18\sl\06

(1)创建一个基于对话框的应用程序,设计对话框资源如图18.11所示。





(2)在对话框的头文件中引用“winsock2.h”头文件,并导入网络库文件。

#include "winsock2.h"
#pragma comment (lib,"ws2_32.lib")

(3)在应用程序的InitInstance方法中初始化套接字。

WSADATA wsd;
WSAStartup(MAKEWORD(2,2),&wsd);

(4)在对话框类中定义成员变量,记录服务器套接字和与之连接的客户端套接字信息。

SOCKET m_server,m_client;
SOCKET m_Clients[MAXNUM];      //客户端套接字
int    m_CurClient;            //当前连接的客户数量

(5)在对话框类的OnInitDialog方法中创建套接字,并初始化数据。

//创建套接字
m_server = socket(AF_INET,SOCK_STREAM,0);
//将网络中的事件关联到窗口的消息函数中
WSAAsyncSelect(m_server,m_hWnd,20000,FD_WRITE|FD_READ|FD_ACCEPT);
m_client = 0;
m_serverIP = "";
for (int i = 0; i< MAXNUM;i++)
m_Clients[i]= 0;
m_CurClient = 0;

(6)处理“监听”按钮的单击事件,将套接字绑定到本机地址,并开始监听套接字。

void CServerDlg::OnOK()
{
//服务器端地址
sockaddr_in serveraddr;serveraddr.sin_family = AF_INET;m_IP.GetWindowText(m_serverIP);//要注意,这里的m_IP是IP控件类型的变量,m_serverIP是CString类型的变量 它们都在类的成员变量中先定义了//设置本机地址
serveraddr.sin_addr.S_un.S_addr  = inet_addr(m_serverIP);UpdateData(TRUE);
//设置端口号
serveraddr.sin_port = htons(atoi(m_port));//m_port也是CString类型的变量//绑定地址
if (bind(m_server,(sockaddr*)&serveraddr,sizeof(serveraddr)))
{
MessageBox("绑定地址失败.");
return;
}
//开始监听
listen(m_server,50);
}

(7)向对话框中添加HandleData方法,用于接受客户端的连接,并获得客户端传来的数据,将其转发给其他客户端。

void CServerDlg::HandleData()
{
sockaddr_in serveraddr;
char buffer[1024];
int len =sizeof(serveraddr);

//接收客户端的数据
int curlink = -1;int num = -1;
for (int p = 0;p< MAXNUM; p++)
{
num= recv(m_Clients[p],buffer,1024,0);
if (num != -1)
{
curlink = p;
break;
}
}
buffer[num]= 0;
if (num==-1) //接受客户端的连接
{
if (m_CurClient < MAXNUM)
{
m_Clients[m_CurClient] = accept(m_server,(struct sockaddr*)
&serveraddr,&len);
m_CurClient+=1;
}
return;
}//将接收的数据发送给客户端(这里是程序的核心,服务器端把接收到的数据又发送出去了)
for (int j = 0;j< m_CurClient;j++)
if (j != curlink)
send(m_Clients[j],buffer,num,0);
}

(8)改写对话框类的PreTranslateMessage方法,在服务器套接字中有事件触发时调用HandleData方法。

BOOL CServerDlg::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message==20000)
{
HandleData();
return TRUE;
}
else
return CDialog::PreTranslateMessage(pMsg);
}

客户端程序设计步骤如下。

ch1807实例位置:mr\18\sl\07

(1)创建一个基于对话框的工程,设置对话框资源如图18.12所示。





图18.12 客户端设计窗口

(2)在对话框类的头文件中引用“winsock2.h”头文件,并导入“ws2_32.lib”库文件。

#include "winsock2.h"
#pragma comment (lib,"ws2_32.lib")

(3)在应用程序的InitInstance方法中初始化套接字。

WSADATA wsd;
WSAStartup(MAKEWORD(2,2),&wsd);

(4)在对话框的OnInitDialog方法中创建套接字。

m_client = socket(AF_INET,SOCK_STREAM,0);

(5)处理“连接”按钮的单击事件,连接服务器,并设置套接字接收数据时触发的消息。

void CClientDlg::OnOK()
{
//服务器端地址
sockaddr_in serveraddr;UpdateData(TRUE);
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(m_port);
serveraddr.sin_addr.S_un.S_addr = inet_addr(m_IP);if (connect(m_client,(sockaddr*)&serveraddr,sizeof(serveraddr))!=0)
{
MessageBox("连接失败");
return;
}
else
MessageBox("连接成功");
WSAAsyncSelect(m_client,m_hWnd,1000,FD_READ);
CString str,info ;
m_name.GetWindowText(str);info.Format("%s------>%s",str,"进入聊天室");
int i = send(m_client,info.GetBuffer(0),info.GetLength(),0);
}

(6)处理“发送”按钮的单击事件,向服务器发送数据。

void CClientDlg::OnButton1()
{
CString str,name,info ;
m_name.GetWindowText(name);
m_info.GetWindowText(str);
if (!name.IsEmpty()&&!str.IsEmpty())
{
info.Format("%s说: %s",name,str);
//开始发送数据
int i = send(m_client,info.GetBuffer(0),info.GetLength(),0);
m_list.AddString(info);
m_info.SetWindowText("");
}
}

(7)向对话框类中添加ReceiveData方法,用于接收从服务器传来的数据。

void CClientDlg::ReceiveData(){
char buffer[1024];
//接收服务器端传来的数据,
int num = recv(m_client,buffer,1024,0);
buffer[num] = 0;
//将接收的数据添加到列表框中
m_list.AddString(buffer);
}

(8)改写对话框的PreTranslateMessage方法,截获对话框的消息,用于接收数据。

BOOL CClientDlg::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message==1000)
{
ReceiveData();
return TRUE;
}
else
return CDialog::PreTranslateMessage(pMsg);
}

运行程序,效果如图18.13、图18.14、图18.15所示。





图18.13 聊天室服务器





图18.14 客户端窗口1





图18.15 客户端窗口2

【责任编辑:阚书 TEL:(010)68476606】
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐