基于Socket的即时通讯系统Word格式.docx
- 文档编号:19970019
- 上传时间:2023-01-13
- 格式:DOCX
- 页数:19
- 大小:398.95KB
基于Socket的即时通讯系统Word格式.docx
《基于Socket的即时通讯系统Word格式.docx》由会员分享,可在线阅读,更多相关《基于Socket的即时通讯系统Word格式.docx(19页珍藏版)》请在冰豆网上搜索。
Socket编程界面由4BSDUNIX首先提出,目的是解决网间网进程通信问题.Socket接口为进程间通信提供了一种新的手段,它不但能用于同一机器中的进程之间的通信,而且支持网络通信功能.Socket具有类型,反应了对用户透明的通信特性.
一个完整的Socket连接用一个相关描述:
{协议,本地地址,本地端口,远地地址,远地端口}
Socket是面向客户-服务器模型而设计的,针对客户和服务器程序提供不同的Socket系统调用.
(2)Socket系统调用
不管Socket内部机制如何,它提供给应用程序员的最终界面是一组系统功能调用.下面,我们一一给出重要的Socket系统调用.
1.创建Socket-----socket()
调用格式如下:
sockid=socket(af,type,protocol)
af:
地址族,指本socket所用地址类型.
type:
类型,指创建socket的应用程序所希望的通信服务器类型.
protocol:
协议,指本socket请求的协议.
2.指定本地地址----bind()调用
bind()将本地socket地址与所创建的socket联系起来,即将本socket地址赋予socket,以指定本地半相关.bind()的作用相当于给socket命名,调用格式为:
bind(sockid,localaddr,addrlen)
sockid:
socket号.
localaddr:
本地socket地址.
addrlen:
地址长度.
3.建立socket连接----connect()与accept()调用
这两个系统调用用于完成整个相关的建立.其中connect用于建立连接.调用格为:
connect(sockid,destaddr,addrlen)
destaddr:
指向对方socket地址(信宿地址)结构的指针.
accept:
用于面向连接的服务器,其调用格式为:
newsock=accept(sockid,clientaddr,paddrlen)
clientaddr:
指向客户socket地址指针.
paddrlen:
客户socket地址长度.
4.listen()调用
此调用用于面向连接服务器,表明它愿意接收连接,listen()在accept()之前调用,格式为:
listen(sockid,quelen)
quelen:
请求队列长度.
5.发送数据----write(),writev(),send()与sendto(),sendmsg()
用于socket数据发送的系统调用一共有五个,其中三个,write(),writev()和send()用于面向连接传输,其余两个用于无连接传输.面向连接的调用可以不指定信宿地址,而无连接的调用必须指定.假如无连接socket的双方均调用过connect(),可以认为是建立有连接的socket,也可以面向连接调用发送数据.
三个面向连接调用三者的格式大致相同:
write(sockid,buff,bufflen):
缓冲发送
writev(sockid,iovector,vectorlen):
集中发送
send(sockid,buff,bufflen,flags):
可控缓冲发送
其中buff指向发送缓冲区的指针,bufflen是发送缓冲区大小.
用于无连接数据发送的调用有两个:
sendto(sockid,buff,bufflen,flags,dsadd,addrlen)
sendmsg(sockid,message,flags):
可控集中无连接发送.
6.接收数据----read(),readv(),recv()与recvfrom(),recvmsg()
接收数据与发送数据系统调用是一一对应的,两者参数的最大区别是,前者buffer是一个指针,其所指单元初值为欲读数据长度,调用后的值是实际读出的值.
4客户--服务器模型的Socket实现框架
1)客户--服务器模型时序图
下图是面向连接客户--服务器模型的典型时序图
服务器
客户
socket()
socket()
bind() bind()
listen()
accept() 等待客户连接请求
阻塞
<
━━━━━━━━━━━━━━━connect()
read()<
━━━━━━━━━━━━━━━>
write()
2)服务器socket地址的确定
在客户--服务器模型中,所有的作用者都是客户首先发起的(如连接请求,服务请求等),因此客户必须要知道服务器socket地址,另外,客户调用服务器之前,可以在命令行中给出服务器所在主机的域名,根据域名可以获得服务器主机的地址,系统调用为:
hp=gethostbyname(host).其中host可以是服务器主机域名,返回hp是一个指向主机地址结构的指针。
五、软件设计(附程序流程图、源程序清单)
1.程序流程图
2.源程序清单
voidCChatRoomDlg:
:
DlgAllInit()
{
CheckRadioButton(IDC_RADIO_CLIENT,IDC_RADIO_SERVER,IDC_RADIO_CLIENT);
SetDlgItemText(IDC_IP_ADDR,_T("
127.0.0.1"
));
//初始化ip地址为本机地址。
SetDlgItemText(IDC_CONNECT_PORT,_T("
5566"
//初始化端口。
SetDlgItemText(IDC_LISTEN_PORT,_T("
EnableWindow(IDC_STOP_CLIENT,FALSE);
EnableWindow(IDC_LISTEN_PORT,FALSE);
EnableWindow(IDC_STOP_SERVER,FALSE);
EnableWindow(IDC_START_SERVER,FALSE);
EnableWindow(IDC_STATIC_LISTEN_PORT,FALSE);
//初始化按键启用or禁用。
EnableWindow(IDC_SENDMSG,FALSE);
}
BOOLCChatRoomDlg:
EnableWindow(UINTuID,BOOLbEnable)
returnGetDlgItem(uID)->
EnableWindow(bEnable);
ExtendDiaog(BOOLbShow)
staticCRectm_DlgRectLarge(0,0,0,0);
staticCRectm_DlgRectSmall(0,0,0,0);
staticCRectm_GroupRectLarge(0,0,0,0);
staticCRectm_GroupRectSmall(0,0,0,0);
//设置窗口大小
if(m_DlgRectLarge.IsRectNull()){
GetWindowRect(&
m_DlgRectLarge);
m_DlgRectSmall=m_DlgRectLarge;
m_DlgRectSmall.right-=220;
:
GetWindowRect(GetDlgItem(IDC_FRAME)->
GetSafeHwnd(),&
m_GroupRectLarge);
m_GroupRectSmall=m_GroupRectLarge;
m_GroupRectSmall.right-=220;
//设置窗口伸缩大小范围
}
if(bShow){
bShowAll=TRUE;
SetWindowPos(NULL,0,0,m_DlgRectLarge.Width(),m_DlgRectLarge.Height(),SWP_NOZORDER|SWP_NOMOVE);
:
SetWindowPos(GetDlgItem(IDC_FRAME)->
GetSafeHwnd(),NULL,0,0,m_GroupRectLarge.Width(),m_GroupRectLarge.Height(),SWP_NOZORDER|SWP_NOMOVE);
}else{
bShowAll=FALSE;
SetWindowPos(NULL,0,0,m_DlgRectSmall.Width(),m_DlgRectSmall.Height(),SWP_NOZORDER|SWP_NOMOVE);
GetSafeHwnd(),NULL,0,0,m_GroupRectSmall.Width(),m_GroupRectSmall.Height(),SWP_NOZORDER|SWP_NOMOVE);
OnBnClickedNetset()
if(bShowAll){
ExtendDiaog(FALSE);
ExtendDiaog(TRUE);
//设置按键“网络设置”的作用
OnBnClickedStartServer()
m_hListenThread=CreateThread(NULL,0,ListenThreadFunc,this,0,NULL);
ShowMsg(CStringstrMsg)
m_MsgEdit.SetSel(-1,-1);
m_MsgEdit.ReplaceSel(strMsg+_T("
\r\n"
RemoveClientFromArray(CClientItemin_Item)
for(intidx=0;
idx<
m_ClientArray.GetCount();
idx++){
CClientItemtItem=m_ClientArray.GetAt(idx);
if(tItem.m_Socket==in_Item.m_Socket&
&
tItem.hThread==in_Item.hThread&
tItem.m_strIp==in_Item.m_strIp){
m_ClientArray.RemoveAt(idx);
}
OnBnClickedSendmsg()
CStringstrMsg;
GetDlgItemText(IDC_INPUT_MSG,strMsg);
if(m_bIsServer==TRUE){
strMsg=_T("
张智超的服务器:
>
"
)+strMsg;
ShowMsg(strMsg);
SendClientsMsg(strMsg);
}elseif(m_bIsServer==FALSE){
CStringstrTmp=_T("
张智超的客户端:
ShowMsg(strTmp);
intiSend=send(m_ConnectSock,(char*)strMsg.GetBuffer(),strMsg.GetLength()*sizeof(TCHAR),0);
strMsg.ReleaseBuffer();
AfxMessageBox(_T("
请您先进入聊天室!
SetDlgItemText(IDC_INPUT_MSG,_T("
}//socket基本应用
OnBnClickedStartClient()
m_hConnectThred=CreateThread(NULL,0,ConnectThreadFunc,this,0,NULL);
SendClientsMsg(CStringstrMsg,CClientItem*pNotSend)
TCHARszBuf[MAX_BUF_SIZE]={0};
_tcscpy_s(szBuf,MAX_BUF_SIZE,strMsg);
for(INT_PTRidx=0;
m_ClientArray.GetCount();
if(!
pNotSend||pNotSend->
m_Socket!
=m_ClientArray.GetAt(idx).m_Socket||pNotSend->
hThread!
=m_ClientArray.GetAt(idx).hThread||
pNotSend->
m_strIp!
=m_ClientArray.GetAt(idx).m_strIp){
send(m_ClientArray.GetAt(idx).m_Socket,(char*)szBuf,_tcslen(szBuf)*sizeof(TCHAR),0);
OnEnChangeInputMsg()
if(strMsg.IsEmpty()){
EnableWindow(IDC_SENDMSG,FALSE);
EnableWindow(IDC_SENDMSG);
StopClient()
bShutDown=TRUE;
DWORDdwRet=WaitForSingleObject(m_hConnectThred,1000);
if(dwRet!
=WAIT_OBJECT_0){
TerminateThread(m_hConnectThred,-1);
closesocket(m_ConnectSock);
m_hConnectThred=NULL;
m_ConnectSock=INVALID_SOCKET;
m_bIsServer=-1;
bShutDown=FALSE;
StopServer()
UINTnCount=m_ClientArray.GetCount();
HANDLE*m_pHandles=newHANDLE[nCount+1];
m_pHandles[0]=m_hListenThread;
nCount;
m_pHandles[idx+1]=m_ClientArray.GetAt(idx).hThread;
DWORDdwRet=WaitForMultipleObjects(nCount+1,m_pHandles,TRUE,1000);
for(INT_PTRi=0;
i<
i++){
TerminateThread(m_ClientArray.GetAt(i).hThread,-1);
closesocket(m_ClientArray.GetAt(i).m_Socket);
TerminateThread(m_hListenThread,-1);
closesocket(m_ListenSock);
delete[]m_pHandles;
m_hListenThread=NULL;
m_ListenSock=INVALID_SOCKET;
OnBnClickedStopClient()
StopClient();
ShowMsg(_T("
停止客户端成功!
EnableWindow(IDC_START_CLIENT);
EnableWindow(IDC_STOP_CLIENT,FALSE);
OnBnClickedStopServer()
StopServer();
停止服务器成功!
EnableWindow(IDC_START_SERVER);
OnBnClickedRadioClient()
intiRet=-1;
intiRet=MessageBox(_T("
您是聊天室的服务器端,如果您退出,所有的客户端都将掉线!
\r\n您确定退出吗?
),_T("
提示"
),MB_OKCANCEL|MB_ICONWARNING);
if(iRet==IDOK){
StopServer();
}else{
CheckRadioButton(IDC_RADIO_CLIENT,IDC_RADIO_SERVER,IDC_RADIO_SERVER);
if(iRet==IDOK||m_bIsServer==-1){
EnableWindow(IDC_IP_ADDR);
EnableWindow(IDC_CONNECT_PORT);
EnableWindow(IDC_STATIC_SERVER_IP);
EnableWindow(IDC_STATIC_SERVER_PORT);
EnableWindow(IDC_START_CLIENT);
EnableWindow(IDC_STOP_CLIENT,FALSE);
EnableWindow(IDC_LISTEN_PORT,FALSE);
EnableWindow(IDC_STOP_SERVER,FALSE);
EnableWindow(IDC_START_SERVER,FALSE);
EnableWindow(IDC_STATIC_LISTEN_PORT,FALSE);
OnBnClickedRadioServer()
if(m_bIsServer==FALSE){
您正在聊天室中,确定退出吗?
),MB_OKCANCEL|MB_ICONWARN
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 基于 Socket 即时通讯 系统
![提示](https://static.bdocx.com/images/bang_tan.gif)