利用Windows Socket编写程序实现客户机/服务器端对端的聊天程序。
1需求分析与开发环境
1.1功能需求
1、单个客户机和服务器通过IP地址和端口号进行连接;
2、接受客户端发送信息显示在一个列表框内;
3、客户端和服务器端可以交流信息,可以收发文件,服务器端可实现监听;
4、当服务器停止服务,向每个连接客户端发送服务终止通告;
5、客户端需要会员登陆,会员数据保存在数据库中,登陆后才可进行聊天;
6、在服务器端添加了文件保存功能,管理员可以对聊天内容进行记录。
1.2开发环境
整个系统采用的是Visual C++ 6.0程序设计,数据库使用的是SQL Server 2005数据库。程序的核心就是要利用Windows Socket进行网络设计实现,使用CS结构。
2数据库设计
由于相对于数据库的要求比较简单,只需要利用SQL Server 2005创建一个数据库,其中创建一个login表存放管理员账户信息就可以了。数据表login信息为:用户名(Uname)、密码(Upw)。
2.1数据库的链接
使用ADO进行数据库设计,需要添加导入语句。
#import "C:\Program Files\Common Files\System\ado\msado15.dll" no_namespace rename("EOF","end")
3各模块的设计
3.1服务器与客户端套接的实现
3.1.1服务器端:
3.1.1.1CMyServerSocket类
主要功能:用于侦听,创建客户CMyServerSocket。
主要成员函数:OnAccept(int nErrorCode)主要功能:重载父类OnAccept(int nErrorCode) 用于在侦听后,接受客户端Connect()时自行调用的函数。
构造函数:CMyServerSocket()功能:就是初始化类参数
析构函数:~ CMyServerSocket();保持默认
3.1.1.2MySocket类
主要功能:对应每一个用户的套接口,实现接受功能。当然也实现发送功能(发送功能没有重载是因为在对话框类内进行了修改)。
主要成员函数:OnReceive(int nErrorCode)和OnSend(int nErrorCode)主要功能:利用类向导重载MySocket的OnReceive(int nErrorCode)和OnSend(int nErrorCode)函数,把缓冲区内容一次发生完毕,在接收时需要把接收到的代码显示在对话框的编辑框内。
构造函数:MySocket(CServerDlg *pDlg)功能:就是初始化类参数
析构函数:~MySocket();保持默认
3.1.2客户端:
3.1.2.1 MySocket类
主要功能:对应每一个用户的套接口,实现接受功能。当然也实现发送功能(发送功能没有重载是因为在对话框类内进行了修改)。
主要成员函数:OnReceive(int nErrorCode)、OnSend(int nErrorCode),、OnConnect(int ErrorCode)主要功能:利用类向导重载MySocket的OnReceive(int nErrorCode)和OnSend(int nErrorCode)函数,把缓冲区内容一次发生完毕,在接收时需要把接收到的代码显示在对话框的编辑框内。OnConnect(int ErrorCode)设置连接信息。
构造函数:MySocket(CServerDlg *pDlg)功能:就是初始化类参数
析构函数:~MySocket();保持默认
3.2服务器端的实现
服务器端登陆,注册界面设计
服务器界面设计图
为控件添加变量,控件ID及变量图
3.2.1登录实现
void CDialog1::Onlogin()
{
UpdateData(true);
CoInitialize(NULL);
_ConnectionPtr pconnect(__uuidof(Connection));
_RecordsetPtr record(__uuidof(Recordset));
_CommandPtr comd(__uuidof(Command));
pconnect->ConnectionString="Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=user";
pconnect->Open("","","",NULL);
comd->put_ActiveConnection(_variant_t((IDispatch *)pconnect));
//标准SQL语句
CString str1;
CString cmd="select * from login where 用户名='";
cmd+=m_name;
cmd+="'and 密码='";
str1.Format("%d",m_pass);
cmd+=str1 ;
cmd+="'";
comd->CommandText=_bstr_t(cmd);//得到SQL语句
record=comd->Execute(NULL,NULL,adCmdText);
if(!record->end)
{
CTest1Dlg dlg;
CTest1App * pApp=(CTest1App*)AfxGetApp();
pApp->m_pMainWnd = &dlg;
dlg.DoModal();
}else
{AfxMessageBox("login error"); }
record->Close();
pconnect->Close();
comd.Relea se();
record.Release();
pconnect.Release();
CoUninitialize();}
注册的实现
void CDialog1::Onzhuce()
{
UpdateData(true);
CoInitialize(NULL);
_ConnectionPtr pconnect(__uuidof(Connection));
_RecordsetPtr record(__uuidof(Recordset));
_CommandPtr comd(__uuidof(Command));
pconnect->ConnectionString ="Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=user";
pconnect->Open ("","","",NULL);
comd->put_ActiveConnection (_variant_t((IDispatch *)pconnect));
CString cmd="insert into login values('";
cmd+=m_name;
cmd+="','";
CString str2;
str2.Format("%d",m_pass);
cmd+=str2;
cmd+="')";
comd->CommandText=_bstr_t(cmd);
if(m_name.IsEmpty()||str2.IsEmpty())
{AfxMessageBox("请输入用户或者密码");
return;
}
else
{
record=comd->Execute(NULL,NULL,adCmdText);//执行sql语句
}
AfxMessageBox("恭喜你,注册成功");
CDialog1::OnOK();
return;
record->Close();
pconnect->Close();
comd.Release();
record.Release();
pconnect.Release();
CoUninitialize();
}
3.2.2创建服务器
创建服务器,客户端可以通过IP地址和端口号和服务器进行连接,实现代码如下:
void CTest1Dlg::OnListen()
{
Info.i=9;
Info.pctrlProgress=&m_progress;
CWinThread* pThread=AfxBeginThread(fun,&Info);
UpdateData(true);
if (!AfxSocketInit())
{
AfxMessageBox("IDP_SOCKETS_INIT_FAILED");
return ;
}
BOOL flag=m_serversocket.Create(m_port);
if(!flag)
{
AfxMessageBox("SOCKET ERROR");
return;
}
flag=m_serversocket.Listen(1);
if(!flag)
{
AfxMessageBox("SOCKET ERROR");
return;
}
SetDlgItemText(IDC_LISTEN,"正在监听");
}
3.2.3发送按钮
用于实现向客户端发送消息的功能实现代码如下:
void CTest1Dlg::OnSend()
{
int ilen;
int isent;
UpdateData(TRUE);
SYSTEMTIME str;
CString strTime;
GetLocalTime(&str);
strTime.Format("%2d:%2d:%2d",str.wHour,str.wMinute,str.wSecond);
if(m_sendmsg!="")
{
ilen=m_sendmsg.GetLength ();
isent=m_serversocket.m_socket->Send(LPCTSTR(m_sendmsg),ilen);
if(isent==SOCKET_ERROR)
{
MessageBox("连接失败,请重试!");
}
else
{
m_msg+="服务器:"+strTime+"发"+m_sendmsg;
//m_msg+= Server_time;
m_msg+="\r\n";
m_sendmsg="";
UpdateData(FALSE);}
}
}
3.2.4服务器退出
void CTest1Dlg::OnOK()
{
// TODO: Add extra validation here
CDialog::OnOK();
}
3.3客户端的实现
客户机聊天界面设计3.3.1连接按钮
与服务器的链接,连接成功可进行聊天操作。实现代码如下:void CTestDlg::OnConnect()
{
if (!AfxSocketInit())
{
AfxMessageBox("IDP_SOCKETS_INIT_FAILED");
return ;
}
GetDlgItemText(IDC_IPADDRESS1,m_ipstr);
m_socket.m_hSocket=INV ALID_SOCKET;
UpdateData(true);
BOOL flag=m_socket.Create();
if(!flag)
{
AfxMessageBox("SOCKET ERROR");
return;
}
m_socket.Connect(m_ipstr,m_port);
}
3.3.2发送按钮
向服务器发送消息,实现代码如下:
void CTestDlg::OnSend()
{
int ilen;
int isent;
UpdateData(1);
SYSTEMTIME str;
CString strTime;
GetLocalTime(&str);
strTime.Format("%2d:%2d:%2d",str.wHour,str.wMinute,str.wSecond); if(m_msg!=" ")
{
ilen=m_msg.GetLength();
isent=m_socket.Send(LPCTSTR(m_msg),ilen);
if(isent==SOCKET_ERROR)
{
MessageBox("连接失败,请重试!");
}
else
{
m_recmsg+="客户机"+strTime+"发"+m_msg;
m_recmsg+="\r\n";
m_msg="";
UpdateData(0);
}
}
}
4程序测试
4.1服务器端操作测试
服务器端登陆界面
服务器端注册界面
打开服务器端进行监听
实现聊天4.2客户端操作测试
实现聊天
5课程设计总结
本次课程设计是运用Visual C++6.0作为开发平台以及Sql数据库来进行编写聊天程序, 在此设计过程中主要经过了审题、需求分析与可行性研究,然后形成设计思路,设计所要实现的功能,最后进行程序的编写与调试,这个过程是不断出现问题并不断的进行修改,深深的感受到亲自动手实践的重要性。在实验的过程中发现学好基础理论知识的重要性,在设计过程中,不断遇到问题,通过老师和同学的帮助,解决了过程中出现的各种问题。
通过本次课程设计,发现了自己的不足,希望在以后的学习中能够加强学习,提高实际应用能力,和解决问题的能力。