1、基于套接字的聊天程序设计TCP/IP课程设计题目: 基于套接字的聊天程序设计院 系:计算机与电子信息学院专 业:网络工程班 级:网络10-2学 号:10034120228姓 名:刘亮日 期:2012.9.25二O一二年编制课程设计任务书一、设计题目基于TCP和UDP套接字的聊天程序设计二、设计目的:(1) 理解客户机/服务器模型的工作原理;(2) 掌握套接字的概念;(3) 掌握基于套接字的面向连接和无连接客户机/服务器程序的设计原理和相关的WinSock API函数;(4) 掌握基于TCP和UDP的程序设计方法。三、设计内容:(一) 基于TCP的应用编程:编写一个Client/Server程序
2、对,服务器程序负责接收客户机进程的连接请求,并在服务器进程与客户机进程之间建立通信连接,然后接收客户机进程的传送数据并将其显示在服务器端,同时将欢迎信息发送给客户机进程,通信结束后关闭该客户机进程的连接;客户机进程首先提出对指定服务器的连接请求,建立连接后向服务器进程发送已经建立连接的数据信息,同时接收服务器进程发送过来的数据并显示在客户端。采用WinSock AIP实现代码。(二) 基于UDP的应用编程:实现一个基于UDP的客户机/服务器程序,通过设定不同的命令行参数来确定应用进程的不同角色,即充当客户机进程还是服务器进程。当两个进程运行后,彼此之间可以轮流发送消息,对方接收后显示出来。四、
3、开发环境和语言:(1)网络:局域网;(2)开发环境:VS2005以上或VC+6.0以上版本;(3)开放语言:C/C+。1 通信原理分析1.1 TCP协议 TCP协议是一种面向连接的、可靠的传输层协议,为应用层提供可靠、全双工的数据流传输服务,TCP报文封装在IP数据报中。在使用TCP进行通信时需要首先建立TCP连接后再能进行数据的传输,TCP连接建立为在不安全的IP网络中传输数据提供了数据完整的保障,在通信结束后要将该连接断开。 下面给出基于TCP的c/s通信工作模式: 服务器进程 客户端进程 1.2 UDP协议UDP是一种无连接、尽最大努力交付的运输层协议,不提供流量控制和确认机制,数据报可
4、能丢失、延迟、乱序到达。这就是的UDP在实现起来就较为简单,这种简单能很好的应用在实时通信服务中,如实时语音传输、实时视频通信等。 下面给出基于UDP的c/s通信工作模式: 进程A 进程B基于udpP的c/s通信模式1.3 套接字的定义 套接字我们可以认为就是通信的一端,其主要包括协议、ip、端口号。将两个套接字连接在一起就可以实现端到端的网络通信了。在套接字中封装了网络和传输层协议,从而为程序员屏蔽了底层通信的复杂性。 针对不同通信的需求,在TCP/IP协议中提供了3种不同套接字类型,分别为: 流式套接字(SOCK_STREAM)、数据保式套接字(SOCK_DGRAM)、原始套接字(SOCK
5、_RAW)。流式套接字(SOCK_STREAM) 提供面向连接的,可靠的数据传输服务,数据无差错,无重复的发送,且按发送的顺序接收,基于 TCP 协议。数据保式套接字(SOCK_DGRAM) 提供无连接的服务,数据包以独立包形式发送,不提供无错误的保证,数据可能丢失或重复,且接收顺序混乱,基于 UDP 协议。原始套接字(SOCK_RAW) 主要是在编写自定义底层协议的应用程序时使用。 1.4 客户机/服务器模式的运行原理 网络应用程序一般是以客户机/服务器的模型的方式工作的。在这种工作方式中,一个服务器程序通常事先启动, 并在一个熟知端口侦听对服务器的请求。当客户机应用程序需要某种服务时,需向
6、提供这种服务的服务器发出请求,服务器在接收到请求后,向客户机发出相应请求信息。这样 客户机应用程序和服务器程序之间便建立了通信连接, 此后可以进行数据通信。通信任务完成后需要关闭它们之间的通信连接。 2 系统设计2.1 基于TCP应用程序设计:2.2 基于UDP应用程序设计:服务器进程登陆,注册信息到服务器请求客户A的ip和端口信息登陆,注册信息到服务器请求客户B的ip和端口信息客户机B进程客户机A进程3 详细设计3.1基于TCP的应用程序设计:3.1.1 服务器设计:#include #include using namespace std;#include int main(int arg
7、c, char *argv) const int DEFAULT_PORT = 5000; WORD wVersionRequested; WSADATA wsaData; int err,iLen; wVersionRequested=MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) cout加载WinSock失败!; return 0; /创建用于监听的套接字 SOCKET sockSrv = socket(AF_INET,SOCK_STREAM,0); /创建服务器监听套接
8、字 if (sockSrv = INVALID_SOCKET) coutsocket() fail:WSAGetLastError()endl; return 0; SOCKADDR_IN addrSrv; char cip20=; int port; char type; cout 服务器基本设置为 ip:127.0.0.1 端口:5000endl; cout 是否从新设置:Y or Ntype; if(type=Y) coutcip; /ip=cip; coutport; addrSrv.sin_family = AF_INET; addrSrv.sin_addr.S_un.S_addr
9、= inet_addr(cip); addrSrv.sin_port = htons(port); else addrSrv.sin_family = AF_INET; addrSrv.sin_addr.S_un.S_addr = inet_addr(127.0.0.1); addrSrv.sin_port = htons(DEFAULT_PORT); /绑定本地主机IP和端口 err = bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR); if ( err != 0 ) coutbind() fail:WSAGetLastError()end
10、l; return 0; coutServer has been started successfully.endl; /监听 err = listen(sockSrv,5); if ( err != 0 ) coutlisten() fail:WSAGetLastError()endl; return 0; coutServer waiting:.endl; SOCKADDR_IN addrClient; int len = sizeof(SOCKADDR); while(1) SOCKET sockConn = accept(sockSrv,(SOCKADDR*)&addrClient,&
11、len);/接收客户进程连接请求 if (sockConn = INVALID_SOCKET) coutaccept() fail:WSAGetLastError()endl; break; char recvBuf1024 = 0; iLen = recv(sockConn,recvBuf,1024,0);/接收数据 if (iLen = SOCKET_ERROR) coutrecv() fail:WSAGetLastError()endl; break; recvBufiLen = 0; coutrecvBufendl; char sendBuf1024,hostname100; if (
12、gethostname(hostname,100) != 0) /获取主机名称 strcpy(hostname,None); sprintf(sendBuf,welcome %s connected to %s!,inet_ntoa(addrClient.sin_addr),hostname); err = send(sockConn,sendBuf,strlen(sendBuf)+1,0); /发送数据 if (err = SOCKET_ERROR) coutsend() fail:WSAGetLastError()endl; break; while(1 ) char recvBuf102
13、4 = 0; iLen = recv(sockConn,recvBuf,1024,0);/接收数据 if (iLen = SOCKET_ERROR) coutrecv() fail:WSAGetLastError()endl; break; recvBufiLen = 0; coutrecvBufendl; cout请输入你要发送的消息,输入E退出sendBuf; string str=sendBuf; if(pare(E) err = send(sockConn,sendBuf,strlen(sendBuf)+1,0); /发送数据 if (err = SOCKET_ERROR) couts
14、end() fail:WSAGetLastError()endl; break; else break; closesocket(sockConn); /关闭套接字 coutServer waiting:.endl; WSACleanup(); return 0; 3.1.2 客户端设计:#include #include using namespace std;#include int main(int argc, char *argv) const int DEFAULT_PORT = 5000; WORD wVersionRequested; WSADATA wsaData; int e
15、rr,iLen; wVersionRequested=MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) cout加载WinSock失败!; return 0; /创建用于连接的套接字 SOCKET sockClient = socket(AF_INET,SOCK_STREAM,0); if (sockClient = INVALID_SOCKET) coutsocket() fail:WSAGetLastError()endl; return 0; SOCKADDR_IN add
16、rSrv; /string ip; char cip20=; int port; char type; cout 服务器基本设置为 ip:127.0.0.1 端口:5000endl; cout 是否从新设置:Y or Ntype; if(type=Y) coutcip; /ip=cip; coutport; addrSrv.sin_family = AF_INET; addrSrv.sin_addr.S_un.S_addr = inet_addr(cip); addrSrv.sin_port = htons(port); else addrSrv.sin_family = AF_INET; a
17、ddrSrv.sin_addr.S_un.S_addr = inet_addr(127.0.0.1); addrSrv.sin_port = htons(DEFAULT_PORT); err = connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR);/请求连接服务器进程 if ( err = INVALID_SOCKET ) coutconnect() fail:WSAGetLastError()endl; return 0; char sendBuf1024,hostname100; if (gethostname(hostname,
18、100) != 0) /获取主机名称 strcpy(hostname,None); strcpy(sendBuf,hostname); strcat(sendBuf, have conneted to you!); err = send(sockClient,sendBuf,strlen(sendBuf)+1,0); /发送数据 if (err = SOCKET_ERROR) coutsend() fail:WSAGetLastError()endl; return 0; char recvBuf1024; iLen = recv(sockClient,recvBuf,1024,0); /接收
19、数据 if (iLen = 0) return 0; else if (iLen = SOCKET_ERROR) coutrecv() fail:WSAGetLastError()endl; return 0; else recvBufiLen = 0; coutrecvBufendl; while(1) char sendBuf1024; cout请输入你要发送的消息,输入E退出sendBuf; string str=sendBuf; if(pare(E) err = send(sockClient,sendBuf,strlen(sendBuf)+1,0); /发送数据 if (err =
20、SOCKET_ERROR) coutsend() fail:WSAGetLastError()endl; return 0; else break; char recvBuf1024; iLen = recv(sockClient,recvBuf,1024,0); /接收数据 if (iLen = 0) return 0; else if (iLen = SOCKET_ERROR) coutrecv() fail:WSAGetLastError()endl; return 0; else recvBufiLen = 0; coutrecvBufOnSend(nErrorCode);/事件响应函
21、数(当一个套接字准备好了,并且可以利用Receive接收时,就可以去调用该函数去处理相应的消息)void CUDPSocket:OnReceive(int nErrorCode) CCUDPServerDlg *pDl = CCUDPServerDlg:GetDialog(); pDl-OnReceive(nErrorCode);/地址和端口绑定bool CUDPSocket:BindLocatePC(DWORD m_LocateIP,int m_LocatePort) in_addr tempAddr; CString buf; /* LPCTSTR类型 L表示long指针 这是为了兼容Wi
22、ndows 3.1等16位操作系统遗留下来的,在win32中以及其他的32为操作系统中, long指针和near指针及far修饰符都是为了兼容的作用。没有实际意义。 P表示这是一个指针;C表示是一个常量;T表示在Win32环境中,有一个_T宏,这个宏用来表示你的字符是否使用UNICODE, 如果你的程序定义了UNICODE或者其他相关的宏,那么这个字符或者字符串将被作为UNICODE字符串,否则就是标准的ANSI字符串。 STR表示这个变量是一个字符串所以LPCTSTR就表示一个指向常固定地址的可以根据一些宏定义改变语义的字符串。同样, LPCSTR就只能是一个ANSI字符串,在程序中我们大部
23、分时间要使用带T的类型定义。LPCTSTR = const TCHAR *=const char * LPCSTR与char的区别 在美国国家标准下,LPCTSTR为const char *,是常量,不可修改;而char,是变量,可以修改。两者的存储位置是不同的,如果强制转换的话,不安全。 */ LPCTSTR p ; /获取本地IP tempAddr.S_un.S_addr = htonl(m_LocateIP); buf = inet_ntoa(tempAddr);/将网络字节的顺序的表示的IP地址转换为点分十进制表示的IP地址 p = (LPCTSTR) buf; /绑定本地IP /*
24、Create函数*/ if (!Create(htons(m_LocatePort),SOCK_DGRAM,FD_READ|FD_WRITE,p) /htons函数是将16位的端口号从主机顺序装换为网络字节顺序,SOCK_DGRAM表示数据报套接字 return false; /设置连接标志 m_fConnected = true; return true ;/向远程主机中发送数bool CUDPSocket:SendToRemotePC(DWORD m_RemoteIP,int m_RemotePort,CString m_SendData) in_addr tempAddr; char send_buf1024 ; CString buf; LPCTSTR p ; /发送数据 if (m_fConne
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1