基于Socket的即时通讯系统.docx

上传人:b****6 文档编号:5729787 上传时间:2022-12-31 格式:DOCX 页数:20 大小:399.42KB
下载 相关 举报
基于Socket的即时通讯系统.docx_第1页
第1页 / 共20页
基于Socket的即时通讯系统.docx_第2页
第2页 / 共20页
基于Socket的即时通讯系统.docx_第3页
第3页 / 共20页
基于Socket的即时通讯系统.docx_第4页
第4页 / 共20页
基于Socket的即时通讯系统.docx_第5页
第5页 / 共20页
点击查看更多>>
下载资源
资源描述

基于Socket的即时通讯系统.docx

《基于Socket的即时通讯系统.docx》由会员分享,可在线阅读,更多相关《基于Socket的即时通讯系统.docx(20页珍藏版)》请在冰豆网上搜索。

基于Socket的即时通讯系统.docx

基于Socket的即时通讯系统

评阅教师评语:

课程设计成绩

考勤成绩

实做成绩

报告成绩

总评成绩

指导教师签名:

《综合课程设计》

设计报告

论文题目:

基于Socket的即时通讯系统

学院(系):

电子信息与自动化学院

班级:

72——1

学生姓名:

学号

指导教师:

时间:

2011年6月7日到2011年6月17日

 

一、设计目的

通过综合课程设计,使学生能够运用《数字信号处理》、《信号与系统》、《通信原理》、《面向对象的程序设计》、《计算机通信网》、《通信协议开发及应用》等课程的知识来设计一个基于Socket的即时通讯系统,培养学生的动手能力以及分析问题、解决问题的能力。

二、设计内容

一个基于Socket的即时通讯系统的多人聊天软件

三、设计要求

(一)基本要求

1.熟练掌握面向对象的程序设计方法;

2.实现点对点通讯,能进行文字对话传输,包括客户端与服务器端;

3.能对系统参数进行配置。

(二)提高要求

1、实现文件、图片传输;

2、语音对话(两人及两人以上);

3、友好的对话界面。

四、设计原理

1TCP/IP简介

  TCP/IP的历史要追溯到70年代中期,当时ARPA为了实现异种网之间的互连(interconnection)与互通(intercommunication),大力资助网间网技术的研究和开发,于1977年到1979年推出目前形式的TCP/IP体系结构和协议规范.到今天,TCP/IP技术以及Internet网间网已经为广大计算机工作者,机算机厂商和机算机用户所接受.据统计,到1990年,Internet以包含遍布欧美的五千个活动网络,超过三十万台机算机.作为一种事实上的工标准,TCP/IP技术方兴未艾.

2TCP/IP的网络分层结构

  对TCP/IP协议来说,TCP提供传输层服务,IP提供网络层服务.TCP/IP协议组(或Internet协议组)的分层结构及其与OSI模型的对应关系如图4所示.图中有关协议的名称及其基本含义如下:

  

(1)TCP. 为传输控制协议(TransmissionControlProtocol).它是提供给用户进程的一个可靠的全双工字节流的面向连接的协议.大多数Internet应用程序使用TCP.因为TCP使用IP,所以整个Internet协议组也常称为TCP/IP协议组.

  

(2)UDP.为用户数据报协议(UserDatagramProtocol).

  (3)ICMP.为网间报文控制协议(InternetControlMessageProtocol).

  (4)IP.网间协议(InternetProtocol).IP协议是为TCP,UDP和ICMP提供分组发送服务协议.

  (5)ARP.地址转换协议.

  (6)RARP.反向地址转换协议.

3Socket编程界面

  

(1)Socket原理

  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("5566"));

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);

}

voidCChatRoomDlg:

:

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);

:

:

SetWindowPos(GetDlgItem(IDC_FRAME)->GetSafeHwnd(),NULL,0,0,m_GroupRectSmall.Width(),m_GroupRectSmall.Height(),SWP_NOZORDER|SWP_NOMOVE);

}

}

voidCChatRoomDlg:

:

OnBnClickedNetset()

{

if(bShowAll){

ExtendDiaog(FALSE);

}else{

ExtendDiaog(TRUE);//设置按键“网络设置”的作用

}

}

voidCChatRoomDlg:

:

OnBnClickedStartServer()

{

m_hListenThread=CreateThread(NULL,0,ListenThreadFunc,this,0,NULL);

}

voidCChatRoomDlg:

:

ShowMsg(CStringstrMsg)

{

m_MsgEdit.SetSel(-1,-1);

m_MsgEdit.ReplaceSel(strMsg+_T("\r\n"));

}

voidCChatRoomDlg:

:

RemoveClientFromArray(CClientItemin_Item)

{

for(intidx=0;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);

}

}

}

voidCChatRoomDlg:

:

OnBnClickedSendmsg()

{

CStringstrMsg;

GetDlgItemText(IDC_INPUT_MSG,strMsg);

if(m_bIsServer==TRUE){

strMsg=_T("张智超的服务器:

>")+strMsg;

ShowMsg(strMsg);

SendClientsMsg(strMsg);

}elseif(m_bIsServer==FALSE){

CStringstrTmp=_T("张智超的客户端:

>")+strMsg;

ShowMsg(strTmp);

intiSend=send(m_ConnectSock,(char*)strMsg.GetBuffer(),strMsg.GetLength()*sizeof(TCHAR),0);

strMsg.ReleaseBuffer();

}else{

AfxMessageBox(_T("请您先进入聊天室!

"));

}

SetDlgItemText(IDC_INPUT_MSG,_T(""));

}//socket基本应用

voidCChatRoomDlg:

:

OnBnClickedStartClient()

{

m_hConnectThred=CreateThread(NULL,0,ConnectThreadFunc,this,0,NULL);

}

voidCChatRoomDlg:

:

SendClientsMsg(CStringstrMsg,CClientItem*pNotSend)

{

TCHARszBuf[MAX_BUF_SIZE]={0};

_tcscpy_s(szBuf,MAX_BUF_SIZE,strMsg);

for(INT_PTRidx=0;idx

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);

}

}

}

voidCChatRoomDlg:

:

OnEnChangeInputMsg()

{

CStringstrMsg;

GetDlgItemText(IDC_INPUT_MSG,strMsg);

if(strMsg.IsEmpty()){

EnableWindow(IDC_SENDMSG,FALSE);

}else{

EnableWindow(IDC_SENDMSG);

}

}

voidCChatRoomDlg:

:

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;

}

voidCChatRoomDlg:

:

StopServer()

{

UINTnCount=m_ClientArray.GetCount();

HANDLE*m_pHandles=newHANDLE[nCount+1];

m_pHandles[0]=m_hListenThread;

for(intidx=0;idx

m_pHandles[idx+1]=m_ClientArray.GetAt(idx).hThread;

}

bShutDown=TRUE;

DWORDdwRet=WaitForMultipleObjects(nCount+1,m_pHandles,TRUE,1000);

if(dwRet!

=WAIT_OBJECT_0){

for(INT_PTRi=0;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;

m_bIsServer=-1;

bShutDown=FALSE;

}

voidCChatRoomDlg:

:

OnBnClickedStopClient()

{

StopClient();

ShowMsg(_T("停止客户端成功!

"));

EnableWindow(IDC_START_CLIENT);

EnableWindow(IDC_STOP_CLIENT,FALSE);

}

voidCChatRoomDlg:

:

OnBnClickedStopServer()

{

StopServer();

ShowMsg(_T("停止服务器成功!

"));

EnableWindow(IDC_START_SERVER);

EnableWindow(IDC_STOP_SERVER,FALSE);

}

voidCChatRoomDlg:

:

OnBnClickedRadioClient()

{

intiRet=-1;

if(m_bIsServer==TRUE){

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_L

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1