操作系统课程设计——多线程通讯-TCP聊天程序-VC++
操作系统课程设计任务书
一、设计题目:多机进程通信
应用Socket进程通信技术编写聊天室程序,实现基于服务器的并发多机信息转发。如果各客户端在线则可以实时聊天、发送接收文件,如果某客户端离线,则发送给他的消息可由服务器端进行内容缓存,待重新连线后可以自动接收通过服务器转发的信息或文件。缓存与转发的控制算法可参考操作系统课程中生产者消费者进程同步方法、缓冲池技术等相关理论。
二、 设计思路和功能的详细描述
采用TCP协议,所以属于客户机/服务器模式,因此需要聊天服务器端和聊天客户端两个程序,实现的功能是:任意一台装有客户端程序的计算机都可以通过服务器端的IP地址与服务器相连,然后进入聊天室与连接到服务器的其他客户进行聊天。当客户聊天结束时,可以点断开与服务器断开连接,以释放进程让其他等待的客户进入聊天室,本聊天室最大同时支持50个客户端的连接,如果服务器配置较高可以修改程序来增加同时连接数。
三、采用的方法、技术、运行环境及其配置
本聊天程序采用TCP协议,用VC++编写,属于客户机/服务器模式。采用了多线程的机制。其中使用windows Sockets实现多台计算机(多个进程)间的通信,SOCKET实际在计算机中提供了一个通信端口,可以通过这个端口与任何一个具有SOCKET接口的计算机通信。应用程序在网络上传输,接收的信息都通过这个SOCKET接口来实现。在客户机/服务器模式中客户应用程序向服务器程序请求服务。一个服务程序通常在一个众所周知的地址监听对服务的请求,也就是说,服务进程一直处于休眠状态,直到一个客户对这个服务的地址提出了连接请求。在这个时刻,服务程序被“惊醒”并且为客户提供服务即对客户的请求作出适当的反应。本聊天程序就是基于这中思想实现的,程序分为两大部分:TCP聊天服务器端和TCP聊天客户端。两者都拥有各自的SOCKET接口,其中服务器端SOCKET接口需要绑定到固定地址上(实现语句:ock=Socket(AF_INET,SOCK_STREAM,0);),等待客户端的连接(实现语句:listen(sock,5);)。等待客户端的连接的过程就是通过多进程机制来实现的。 聊天程序是在VISUAL C++6.0上编译实现的,在WINDOWS2000,XP上测试运行成功。 对客户计算机配置无特殊要求,由于所设置的最大连接进程为50,所以对服务器要求也不高。
四、关键源程序及其详细的注释
<一>、服务器端:
1、Socket初始化 //初始化对话框
BOOL CCSocketDlg::OnInitDialog() { count=0;
m_list.InsertColumn(0,\消息\
m_list.SetColumnWidth(0,435);
m_edit.SetLimitText(99);
for (int i=0;i<50;i++)//初始化SOCKET数组
msgsock=NULL; serv.sin_addr.s_addr=htonl(INADDR_ANY); //设定地址 serv.sin_family=AF_INET; serv.sin_port=5000;//htons(5000); addlen=sizeof(serv); m_button.EnableWindow(FALSE); sock=socket(AF_INET,SOCK_STREAM,0); //创建socket if (bind(sock,(sockaddr*)&serv,addlen)) //绑定 { m_edit.SetWindowText(\绑定错误\ }else { m_edit.SetWindowText(\服务器创建成功\显示提示信息,表示服务器创建成功 listen(sock,5); //开始侦听 AfxBeginThread(&thread,0); //调用线程 } return TRUE; } 2、接收线程 //服务器线程 UINT thread(LPVOID p) { char buff[100];//定义缓冲区 CSize size; size.cx=0; size.cy=30; int s=1,msgcount,loop=1,flag=0; CCSocketDlg *dlg=(CCSocketDlg*)AfxGetApp()->GetMainWnd();//获得当前运行对话框句柄 msgcount=dlg->getcount();//获取还没有被占用的数组序号 if (msgcount==-1)//如果不等于-1,则表示,还有空缺SOCKET loop=0; if(loop) { s=1; dlg->msgsock[msgcount]=accept(dlg->sock,(sockaddr*)&(dlg->serv),&(dlg->addlen));// 用空缺的SOCKET等待客户连接 if (dlg->msgsock[msgcount]==INVALID_SOCKET) { dlg->m_edit.SetWindowText(\如果返回错误,则提示错误 } else { AfxBeginThread(thread,0);//如果和客户端连接成功,则再次启动一个线程 dlg->SetForegroundWindow();//显示连机成功信息 dlg->m_list.InsertItem(dlg->count++,\连接成功\ dlg->m_list.InsertItem(dlg->count++,inet_ntoa(dlg->serv.sin_addr)); dlg->m_list.Scroll(size); dlg->m_button.EnableWindow(TRUE); while(s!=SOCKET_ERROR)//如果没有发生错误,则一直循环等待数据的到来 { s=recv(dlg->msgsock[msgcount],buff,100,0); //循环接收数据 dlg->SetForegroundWindow(); if (s!=SOCKET_ERROR)如果接收成功,则显示接收到的数据 {