基于TCP的简单一对一聊天程序设计一、课程设计目的1、通过课程设计,使学生理论联系实际,在实践中进一步了解计算机网络体系结构,深入理解TCP/IP参考模型2、培养学生分析、解决问题的能力,提高学生动手能力。3、使学生掌握搜集资料、调查研究、整理报告的方法。4、初步掌握网络应用程序开发技术以及互联网的应用技术。二、课程设计的要求及原理1、课程设计要求。实现一个一对一的聊天程序。其基本过程如下:服务器首先启动,创建套节字等待客户连接;客户启动以后,创建套届字,然后和服务器建立连接;连接建立以后,客户机和服务器可以通过建立的套节字连接进行通信。服务器和客户端可以是一台电脑上的两个进程,也可以使分别部署在两台电脑上。2、课程设计原理。客户服务器模型。它是指客户/服务器模型是所有网络应用的基础。客户/服务器分别指参与一次通信的两个应用实体,客户方主动地发起通信请求,服务器方被动地等待通信的建立。它是一个在建立分布式应用时最常用的范例。在这种方案中客户应用程序向服务器程序请求服务。这种方式隐含了在建立客户机/服务器间通讯时的非对称性。客户机/服务器模型工作时要求有一套为客户机和服务器所共识的惯例来保证服务能够被提供(或被接受)。这一套惯例包含了一套协议。它必须在通讯的两头都被实现。根据不同的实际情况,协议可能是对称的或是非对称的。在对称的协议中,每一方都有可能扮演主从角色;在非对称协议中,一方被不可改变地认为是主机,而另一方则是从机。无论具体的协议是对称的或是非对称的,当服务被提供时必然存在客户进程和服务进程。一个服务程序通常在一个众所周知的地址监听对服务的请求,也就是说,服务进程一直处于休眠状态,直到一个客户对这个服务的地址提出了连接请求。在这个时刻,服务程序被惊醒并且为客户提供服务-对客户的请求作出适当的反应。虽然基于连接的服务是设计客户机/服务器应用程序时的标准,但有些服务也是可以通过数据报套接口提供的。相关协议。应用到的网络协议主要有TCP协议。TCP协议被称作一种端对端协议。这是因为它为两台计算机之间的连接起了重要作用:当一台计算机需要与另一台远程计算机连接时,TCP协议会让它们建立一个连接、发送和接收资料以及终止连接。传输控制协议TCP协议利用重发技术和拥塞控制机制,向应用程序提供可靠的通信连接,使它能够自动适应网上的各种变化。即使在Internet暂时出现堵塞的情况下,TCP也能够保证通信的可靠。IP协议只保证计算机能发送和接收分组资料,而TCP协议则可提供一个可靠的、可流控的、全双工的信息流传输服务。三、设计方案首先本程序的定位是一对一的聊天程序;程序没有采用图形界面;程序的设计语言采用的是C++;基于winsock;开发工具为VC++。聊天程序的设计可以采用UDP或者TCP,程序采用TCP。采用的是客户服务器模型。在本程序中,一个用户作为Server端,另一个用户作为Client端。也就是说,作为Server端的用户,需要首先启动程序,等待Client端的连接请求。Client端自动建立连接请求。当TCP连接握手以后,双方方可进行交互。在客户端用户进行消息的编写,发送和接受等功能;而服务器端发送的消息向客户端所有的用户进行发送可以称之为系统消息;服务器端收到某一个用户发送的消息之后可以向所有的其它用户进行转发。连接断开之后,断开服务的客户端将不能够收到服务器转发的消息。程序可在同台机器上或者是不同机器上运行。在用C++语言进行代码的编写时主要应用到的是C++中的网络编程、输入输出处理、多线程以技术。数据的传输使用的是I/O输入输出处理,用到类似coutstring;等的输出处理方法。因为服务器是一只提供服务的,也就是说服务器一直是运行的状态,时刻等待着新的客户端提出连接请求,所以就需要使用到多线程的方法。Socket类的实例的accept方法是一个阻塞式的方法,如果只是用进程来表示新的客户端,那么在现有进程没有结束的情况下,新的客户端在发送连接请求之后程序将不能继续向下执行,所以应该应用比进程更小的线程来解决这一问题。四、程序编写1、客户端与服务器端用到的相关类classCIPMessage{public:CIPMessage();~CIPMessage();voidInit(stringsIpAddress,intiPort);intSendMessagePort(stringsMessage);intRecMessagePort();boolIsConnected(){returnm_bIsConnected;}private:boolm_bIsConnected;//true-connectedfalse-notconnectedstringm_sServerIPAddress;intm_iServerPort;SOCKETconn;//socketconnectedtoserver};classCChatServer{public:CChatServer();~CChatServer();boolIsConnected(){returnm_bIsConnected;}//返回连接状态voidStartListenClient();//ListentoclientintSendMessagePort(stringsMessage);//向所有客户端发消息intRecClient(SOCKETsRecSocket);//接收客户端数据private:boolm_bIsConnected;//true-connectedfalse-notconnectedintm_iServerPort;listSOCKETm_vClientList;//AllsocketconnectedtoclientSOCKETm_SClient;SOCKETm_SListenClient;//socketlisteningforclientcalls};2、服务器端程序#includeserver.hCChatServerCServerObj;UINTServerRecThread(LPVOIDpParam)//接收数据的工作线程{.............}UINTServerListenThread(LPVOIDpParam)//监听端口建立连接的工作线程{.............}CChatServer::CChatServer()//对象CChatServer的构造函数{...........m_SListenClient=socket(AF_INET,SOCK_STREAM,0);//创建一个套接字,返回套接字描述字..............if(bind(m_SListenClient,(sockaddr*)&local,sizeof(local))!=0)//把本地协议的地址赋予一个套接字..............if(listen(m_SListenClient,10)!=0)//监听该端口..............}CChatServer::~CChatServer()//对象CChatServer的析构函数{closesocket(m_SListenClient);//关闭该端口WSACleanup();}voidCChatServer::StartListenClient(){...........m_SClient=accept(m_SListenClient,(structsockaddr*)&from,&fromlen);//产生与客户进行TCP连接通信的套接字并返回已连接客户端的协议地址.............AfxBeginThread(ServerRecThread,(void*)m_SClient);//启动接收线程,用m_SClient套接字与客户端通话}intCChatServer::SendMessagePort(stringsMessage)//向各个客户端发送服务器数据{......for(itl=m_vClientList.begin();itl!=m_vClientList.end();itl++){iStat=send(*itl,sMessage.c_str(),sMessage.size()+1,0);...........}............}intCChatServer::RecClient(SOCKETsRecSocket)//接收客户端数据成员函数{.............iStat=recv(sRecSocket,temp,4096,0);if(iStat==-1){}else{SendMessagePort(temp);..........}return0;}intmain(intargc,char*argv[]){.............if(!CServerObj.IsConnected())//判断监听端口是否建立{...........}AfxBeginThread(ServerListenThread,0);//启动监听端口建立连接的工作线程while(gets(buf)){........if(CServerObj.SendMessagePort(buf)){.............}}..............}3、客户端程序#includeclient.h//GlobalMessageobjectCIPMessageMyMessObj;CIPMessage::CIPMessage()//MyMessObj构造函数{.............}voidCIPMessage::Init(stringsIpAddress,intiPort)//建立与服务器端得连接{................conn=socket(AF_INET,SOCK_STREAM,0);//建立客户端套接字.............addr=inet_addr(m_sServerIPAddress.c_str());//转化ip地址和端口为指定形式hp=gethostbyaddr((char*)&addr,sizeof(addr),AF_INET);..........if(connect(conn,(structsockaddr*)&server,sizeof(server)))//向指定服务器建立连接{..........}m_bIsConnected=true;return;}CIPMessage::~CIPMessage()//MyMessObj析构函数{............}intCIPMessage::SendMessagePort(stringsMessage)//向指定服务器发出数据{...........iStat=send(conn,sMessage.c_str(),sMessage.size()+1,0);...........}intCIPMessage::RecMessagePort()//接收指定服务器数据{..........iStat=recv(conn,acRetData,4096,0);..........}UINTMessageRecThread(LPVOIDpParam)//接收指定服务器数据线程{..............}intmain(intargc,char*argv[]){.............FILE*fp=fopen(server.ini,r);//获取服务器端套接字地址.............while((fgets(buf,4096,fp))!=NULL){........sServerAddress=buf;}fclose(fp);...............MyMessObj.Init(sServerAddress.c_str(),8084);//启动与服务器连接...............AfxBeginThread(MessageRecThread,0);//