毕业设计(论文)-基于linux下网络聊天室的设计与实现.docx_第1页
毕业设计(论文)-基于linux下网络聊天室的设计与实现.docx_第2页
已阅读5页,还剩27页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

linux下网络聊天室的设计与实现前面的各种介绍尽量简略一点,主要介绍该系统的设计和实现,比如需求分析、总体设计、详细设计等,多做一些图。还可以截一些图,代码作为附录放到最后。林仁明计算机学院通信工程专业2008级 指导老师:岳淼 摘要: 本系统采用c/s结合的结构,客户端与客户端以及客户端与服务器端之间通过基于tcp/ip协议socket套接口传送消息。服务器设计与实现过程中采用了多线程技术,可以在单个程序当中同时运行多个不同的线程执行不同的任务。大大增强了程序对服务器资源的利用。在linux下编写并调试服务器端程序和客户端程序,实现了客户、服务器之间的连接和通信。可以在单机上开辟两个窗口实现客户端和服务器,或者两台主机链接分别作为客户端和服务器。总体来说,此设计以嵌入式c语言为开发语言,使用网络套接字socket建立连接,并运行多线程实现数据交换,程序经gcc调试成功,可以在单机网络中使用。关键字:tcp/ip;linux;socketdesign and implementation of internet chat rooms under linuxlinren mingof computer science, communication engineering 2008 instructor: yue miaoabstract: this system uses a combination of c / s structure, between the client and the client and customer client and server-side through the tcp / ip protocol-based socket sets of interfaces to deliver messages. used in server design and implementation of multi-threading technology, in a single program which is running a number of different threads to perform different tasks. greatly enhanced the program on the use of server resources. to write and debug server-side program and client program under linux, the connection between the client, server and communications. two windows can be opened up on a stand-alone client and server, or the two hosts links, respectively, as the client and server. overall, this design embedded c language for the development of language, the use of network sockets socket connection is established and run multi-threaded data exchange program gcc debugging can be used in stand-alone network.keywords: tcp / ip; the linux; the socke目录摘要1abstract1第一章:绪论31.1 什么是网络编程31.2 优点3第二章 linux网络聊天室设计思想42.1 功能分析42.2 总体设计4第三章 linux网络聊天室工具概述53.1 gcc53.1.1 gcc 简介53.1.2 gcc 执行过程53.1.3 gcc 基本使用方法63.2 gnu makefile63.2.1 makefile简介63.2.2 makefile 规则73.3 gdb 调试73.3.1 用gdb调试 gcc 程序7第四章 关键技术分析84.1 linux线程间通信84.1.1.线程概述84.1.2.线程实现84.1.3 线程数据处理94.3 基于linux的socket网络编程94.3.1 端口和套接口94.3.2 套接字和套接口地址结构104.3.3 基本转换函数114.3.4 socket()和bind()函数124.3.5 listen()和accept()函数124.3.6 socket中tcp的三次握手建立连接详解134.3.7、socket中tcp的四次握手释放连接详解14第五章 linux下socket编程实现过程155.1 聊天室socket编译链接过程155.1 具体操作16参考文献:18附录18附录a: multithread_tcp_server.c18附录b: multithread_tcp_client.c23附录c: client_data.c26附录d: user_list.c27致谢30第一章:绪论1.1 什么是网络编程网络编程就是通过使用套接字来达到进程间通信目的编程。网络编程可以做如下工作:网络安全,通讯设备研发,协议分析,网络管理系统等。单就网络编程来说,linux和windows其实都差不多,只是基于不同的开发平台,并且linux的api基本上是自己用c写的,而windows底层有封装,只要熟悉linux网络编程,如果以后转windows相对容易。1.2 优点1、linux作为一个开源的操作系统利于使用人员交流学习而且linux 的许多特性有利于网络编程。首先,linux系统拥有许多网络编程的库函数,可以方便地实现客户机/ 服务器模型。其次linux 秉承了unix 的设备无关性这一优秀特征,即它通过文件的描述符实现了统一的设备接口,网络的socket数据传输是一种特殊的i/ 0 scoket 也是一种文件描述符。再有,且其内核小、效率高、兼容性好和稳定性强等优点。 2、socket接口是一个通用的接口,它不仅支持各种网络工作形式而且还是一个交互式通讯机制。一个套接字描述一个通讯连接的一端。套接字可以被看做一个专门的管道,但又不像管道,套接字对它们能容纳的数量没有限制,且linux支持多种类型的套接字。3、目前计算机网络持续而高速地发展,其中基于tcp/ ip 协议网络已经成为计算机之间组网的常见形式. 基于tcp/ ip 的网络编程,也得到了广泛的应用。tcp/ip这个种网络协议是internet的基础协议。它是一组计算机通信协议族具有开放式互联环境很容易实现各种局域网和广域网的集成式互联。socket通讯所采用的协议分为面向连接和面向非连接两种,由于udp尽最大努力但提供不可靠的服务简单的udp算法可以在本地网络条件好的环境中良好工作,但在环境较复杂的网络中就不能正常工作了,必须通过超时和重传来实现可靠性,而tcp则提供了数据传输的完全可靠性,因此选择tcp通信协议更可靠些。 第二章 linux网络聊天室设计思想2.1 功能分析本系统是想在linux系统下实现一个聊天室系统,只要有服务器和客户端。它具备的基本功能包括注册、登陆、一对一私聊、查看在线人数等。1、 服务器端:负责处理用户发来的各种信息,管理用户的动作(注册、登陆、一对一私聊、查看在线人数)和管理用户的信息。2、 客户端:主要用于查看在线人数、发送信息给特定用户等功能,2.2 总体设计本聊天室系统采用了c/s形式。服务器主要是处理客户输入信息。首先要存储客户的个人资料,相当于注册。再有,在客户的聊天信息时,也要记录下客户的聊天记录,已备查看聊天记录所用。当然,服务器还有自己的动态数据处理。客户状态分为链接客户和非连接客户,我采用结构体存储链接客户信息,以链表来记录链接客户。而链接客户又分为登陆客户和未登陆客户,这就通过修改链表上客户的名字。当客户一链接客户服务端时,就给客户一个账号,也就是相当于注册信息,同时并发服务器一直在为连接用户创建线程,系统的总设计框图如下:第三章 linux网络聊天室工具概述3.1 gcc 3.1.1 gcc 简介gcc(gnu compiler collection,gnu编译器套装),是一套由 gnu 开发的编程语言编译器。它是一套以 gpl 及 lgpl 许可证所发行的自由软件,也是 gnu计划的关键部分,亦是自由的类unix及苹果电脑 mac os x 操作系统的标准编译器。 gcc 原名为 gnu c 语言编译器,因为它原本只能处理 c语言。gcc 很快地扩展,变得可处理 c+。之后也变得可处理 fortran、pascal、objective-c、java, 以及 ada与其他语言。3.1.2 gcc 执行过程虽然我们称gcc是c语言的编译器,但使用gcc由c语言源代码文件生成可执行文件的过程不仅仅是编译的过程,而是要经历四个相互关联的步骤预处理(也称预编译,preprocessing)、编译(compilation)、汇编(assembly)和链接(linking)。 命令gcc首先调用cpp进行预处理,在预处理过程中,对源代码文件中的文件包含(include)、预编译语句(如宏定义define等)进行分析。接着调用cc1进行编译,这个阶段根据输入文件生成以.o为后缀的目标文件。汇编过程是针对汇编语言的步骤,调用as进行工作,一般来讲,.s为后缀的汇编语言源代码文件和汇编、.s为后缀的汇编语言文件经过预编译和汇编之后都生成以.o为后缀的目标文件。当所有的目标文件都生成之后,gcc就调用ld来完成最后的关键性工作,这个阶段就是连接。在连接阶段,所有的目标文件被安排在可执行程序中的恰当的位置,同时,该程序所调用到的库函数也从各自所在的档案库中连到合适的地方。3.1.3 gcc 基本使用方法在使用gcc编译器的时候,我们必须给出一系列必要的调用参数和文件名称。gcc编译器的调用参数大约有100多个,其中多数参数我们可能根本就用不到,这里只介绍其中最基本、最常用的参数。 gcc最基本的用法是gcc options filenames 其中options就是编译器所需要的参数,filenames给出相关的文件名称。 -c,只编译,不连接成为可执行文件,编译器只是由输入的.c等源代码文件生成.o为后缀的目标文件,通常用于编译不包含主程序的子程序文件。 -o output_filename,确定输出文件的名称为output_filename,同时这个名称不能和源文件同名。如果不给出这个选项,gcc就给出预设的可执行文件a.out。 -g,产生符号调试工具(gnu的gdb)所必要的符号资讯,要想对源代码进行调试,我们就必须加入这个选项。 -o,对程序进行优化编译、连接,采用这个选项,整个源代码会在编译、连接过程中进行优化处理,这样产生的可执行文件的执行效率可以提高,但是,编译、连接的速度就相应地要慢一些。 -o2,比-o更好的优化编译、连接,当然整个编译、连接过程会更慢。 -idirname,将dirname所指出的目录加入到程序头文件目录列表中,是在预编译过程中使用的参数。c程序中的头文件包含两种情况 a)#include b)#include “myinc.h” 其中,a类使用尖括号(),b类使用双引号(“ ”)。对于a类,预处理程序cpp在系统预设包含文件目录(如/usr/include)中搜寻相应的文件,而b类,预处理程序在目标文件的文件夹内搜索相应文件。3.2 gnu makefile 3.2.1 makefile简介 makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个 目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个shell脚本一样,其中也可以执行操作系统的命令。makefile带来的好处就是“自动化编译”,一旦 写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工 具,一般来说,大多数的ide都有这个命令,比如:delphi的make,visual c+的nmake,linux下gnu的make。可见,makefile都成为了一种在工程方面的编译方法。3.2.2 makefile 规则target . : prerequisites .command.target也就是一个目标文件,可以是object file,也可以是执行文件。prerequisites就是,要生成那个target所需要的文件或是目标。command也就是make需要执行的命令。(任意的shell命令)这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。说 白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。这就是 makefile的规则。也就是makefile中最核心的内容。3.3 gdb 调试3.3.1 用gdb调试 gcc 程序为调试编译代码(compiling code for debugging)为了使 gdb 正常工作, 你必须使你的程序在编译时包含调试信息。 调试信息包含你程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号。gdb利用这些信息使源代码和机器码相关联。在编译时用 -g 选项打开调试选项。 gdb 基本命令 gdb 支持很多的命令使你能实现不同的功能。 这些命令从简单的文件装入到允许你检查所调用的堆栈内容的复杂命令下面列出了你在用 gdb 调试时会用到的一些命令。如file 装入想要调试的可执行文件。kill 终止正在调试的程序。list 执行一行源代码但不进入函数内部。next 执行一行源代码但不进入函数内部。step 执行一行源代码而且进入函数内部。run 执行当前被调试的程序。quit 终止 gdb。watch 使你能监视一个变量的值而不管它何时被改变。break 在代码里设置断点, 这将使程序执行到这里时被挂起。make 使你能不退出 gdb 就可以重新产生可执行文件。shell 使你能不离开 gdb 就执行 unix shell 命令。gdb 支持很多与 unix shell 程序一样的命令编辑特征。你能象在 bash 或 tcsh里那样按 tab 键让 gdb 帮你补齐一个唯一的命令, 如果不唯一的话 gdb 会列出所有匹配的命令你也能用光标键上下翻动历史命令。第四章 关键技术分析4.1 linux线程间通信4.1.1.线程概述线程是一个进程内的基本调度单位,也可以称为轻量级进程。线程是在共享内存空间中并发的多道执行路径,它们共享一个进程的资源,如文件描述和信号处理。因此,大大减少了上下文切换的开销。一个进程可以有多个线程,也就是有多个线程控制表及堆栈寄存器,但却共享一个用户地址空间。4.1.2.线程实现1、线程创建pthread_create() 所需头文件#include 函数原型int pthread_create (pthread_t *thread, pthread_attr_t *attr,void *(*start_routine)(void *), void *arg)thread:线程标识符attr:线程属性设置start_routine:线程函数的起始地址arg:传递给start_routine的参数函数返回值 成功:0 出错:-12、线程退出pthread_exit();所需头文件#include 函数原型void pthread_exit(void *retval)函数传入值retval:pthread_exit()调用者线程的返回值,可由其他函数如pthread_join 来检索获取3、等待线程退出并释放资源pthread_join() 所需头文件#include 函数原型int pthread_join (pthread_t th, void *thread_return)函数传入值th:等待线程的标识符thread_return:用户定义的指针,用来存储被等待线程的返回值(不为null时)函数返回值 成功:0 出错:-14.1.3 线程数据处理线程数据处理和进程相比,线程的最大优点之一是数据的共享性,各个进程共享父进程处沿袭的数据段,可以方便的获得、修改数据。但这也给多线程编程带来了许多问题。我们必须当心有多个不同的进程访问相同的变量。许多函数是不可重入的,即同时不能运行一个函数的多个拷贝(除非使用不同的数据段)。在函数中声明的静态变量常常带来问题,函数的返回值也会有问题。因为如果返回的是函数内部静态声明的空间的地址,则在一个线程调用该函数得到地址后使用该地址指向的数据时,别的线程可能调用此函数并修改了这一段数据。在进程中共享的变量必须用关键字volatile来定义,这是为了防止编译器在优化时(如gcc中使用-ox参数)改变它们的使用方式。为了保护变量,我们必须使用信号量、互斥等方法来保证我们对变量的正确使用。4.3 基于linux的socket网络编程4.3.1 端口和套接口若一台主机上同时有多个应用程序运行,他们都有可能使用tcp或udp协议进行通信,则传输层协议收到数据后如何区分数据是传给哪一个应用程序的呢?为此引用了端口和套接口。端口:标识传输层与应用程序的数据接口(服务访问点sap),每个端口有一个16位的标识符,称为端口号。套接口:ip地址与端口号的组合,用来标识全网范围内的唯一一个端口,在tcp协议中用来标识一个连接。网络应用程序之间通过套接口来实现通信。常用的socket类型有三种:流式套接口、数据报式套接口和原始套接口。流式是一种面向连接的socket,针对于面向连接的tcp服务应用;数据报式socket是一种无连接的socket,对应于无连接的udp服务应用;原始套接口是针对网络层编程用的套接口,例如ping命令的编写要用到原始套接口,因为ping的底层协议是icmp,而icmp属于网络层。tcp/ip协议模型及各层所用协议如图所示。应用层传输层网络层通信子网层http,telnet,ftp, dns,rip,snmptcptcpieee802.3,fddi,ppp,ip端口sapsaparp ,rarpicmp ,igmp tcp/ip协议模型及各层所用协议4.3.2 套接字和套接口地址结构套接字是套接口描述字的简称,是整型数字,它于文件描述符共用一段数值空间065535。应用程序中使用套接字来调用套接口,套接字可认为是指向套接口的指针,就像文件描述符是指向文件的指针一样。套接字和端口号是最容易混淆的两个概念,套接字不是人为指定的,而是由socket()的返回返回值决定的。一般来说,该套接字(文件描述符号)是系统当前可用的,并且是数值最小的整型描述符;端口号是客户应用程序中一般不认为指定, 而在服务器应用程序中必须指定,以为服务器应用程序要在某个固定端口上监听。linux支持多种套接口地址结构,在这儿只介绍一下ipv4套接口地址结构和通用套接口地址结构。struct sockaddr unsigned short sa_family; /* 地址族, af_xxx */char sa_data14; /* 14字节的协议地址 */;sa_family一般为af_inet;sa_data则包含该socket的ip地址和端口号。ipv4套接口地址结构struct sockaddr_in的定义如下:struct sockaddr_inshort int sin_family;/* 地址族 */unsigned short int sin_port; /* 端口号 */struct in_addr sin_addr; /* internet地址 */unsigned char sin_zero8; /* 添0(和struct sockaddr一样大小*/;指向sockaddr_in 的指针和指向sockaddr的指针可以相互转换,这意味着如果一个函数所需参数类型是sockaddr时,你可以在函数调用的时候将一个指向sockaddr_in的指针转换为指向sickaddr的指针;或者相反。sin_family通常被赋值af_inet;sin_port和sin_sddr应该转换成为网络字节优先顺序;struct in_addr其定义如下:struct in_addrunsigned long s_addr;如果你声明了一个ina作为一个struct sockaddr_in的结构,那么ina.sin_addr.s_addr就是4个字节的ip地址(按网络字节顺序排放)4.3.3 基本转换函数网络字节顺序因为每一个机器内部对变量的字节存储顺序不同(有的系统是高位在前,地位在后,而有的系统是低位在前,高位在后),而网络传输的数据是一定要统一顺序的。所以对与内部字节表示顺序和网络字节顺序不同的机器,一定要对数据进行转换(比如ip地址的表示,端口号的表示)。1. 有关的转换函数套接字字节转换程序的列表:htons() “host to network short”主机字节顺序转换网络字节顺序(对无符号短型进行操作4 bytes)。htonl() “host to network long” 主机字节顺序转换网络字节顺序(对无符号短型进行操作8 bytes)。ntohs() “network to host short”网络字节顺序转换为主机字节顺序(对无符号短型进行操作4 bytes)。ntohl() “network to host long” 网络字节顺序转换为主机字节顺序(对无符号长型进行操作8 bytes)。2. ip地址转换函数inet_addr(),它能够把一个用数字和点表示ip地址的字符串转换成一个无符号长整型。假设有一个struct sockaddr_in ina,并且ip是2,想把它存储到ina,可以使用inet_addr()。ina.sin_addr.s_addr = inet_addr(“2”);(注:inet_addr()返回的地方已经是网络字节顺序了)也可以把一个struct in_addr代表的ip地址打印出来(按照 数字.数字.数字.数字的格式)如printf(“%s”,inet_ntoa(ina.sin_addr) );4.3.4 socket()和bind()函数原型:int socket(int domain,int type, int protocol).功能:创建指定类型的套接口并返回套接口描述符。参数说明:domain参数指定socket的域名,为af_inet或af_unix; type指定套接口的类型,为sock_stream、sock_dgram或sock_raw;protocol通常赋值“0”。原型:int bind(int sockfd, struct sockaddr *my_addr ,int addrlen).功能:使套接口与ip地址和端口号绑定。参数说明:sockfd是一个socket描述符,my_addr是一个指向包含有本机ip地址及端口号等信息的sockaddr类型(通用套接口地址类型)的指针;addrlen 常被设置为sizeof(struct sockaddr).另外,可以用下面的赋值实现自动获得本机ip地址和随即机获取一个没有被占用的端口号:my_addr.sin_port = 0;/*系统随机选择一个未被使用的端口号*/my_addr.sin_addr.s_addr = inaddr_any;/*填入本机ip地方*/原型:close(sockfd);功能:关闭套接字,执行close()之后,套接字将不再允许进行读操作和写操作。说明:sockfd是一个要关闭的套接字。4.3.5 listen()和accept()函数原型:int connect( int sockfd,struct sockaddr *serv_addr,int addrlen);功能:用来与远端服务器建立一个tcp连接。参数说明:sockfd是本地的sockfd描述符;serv_addr是包含目的主机ip地址和端口号的指针。原型:int listen(int sockfd, int backlog);功能:socket与某一端口捆绑以后,就需要监听该端口,以便到达的服务请求加以处理。参数说明:sockfd是socket()系统调用返回的socket描述符;backlog指定在请求队列中允许的最大请求数,进入的连接请求将在队列中等待被accept()。原型:int accept(int sockfd, void *addr,int *addrlen );功能:接受连接队列的服务请求,并返回一个新的socket描述符,来供这个新连接来使用。参数说明:sockfd是被监听的socket描述符,addr通常是一个指向sockaddr_in变量的指针,该变量用来存放提出请求服务的主机的信息(某台主机从某个端口发出该请求);addrlen通常为一个指向值为sizeof(struct sockaddr_in)的整型指针变量。返回值:整型套接口描述符。 在这里须注意,服务器并不是通过监听端口来与客户连接并通信,而是产生一个新的套接口与客户通信。例如web服务器在80号端口监听,当有客户向80号端口发出连接请求时(如图32所示),服务器将接受请求且由服务器进程派生出子进程和新的套接口(由accept()的返回值指向)来与客户连接并通信(如图所示)。listenfdclient 图 客户向服务器监听端口发连接clientlistenfdconnfd 图 服务器accept()后与客户建立连接4.3.6 socket中tcp的三次握手建立连接详解我们知道tcp建立连接要进行“三次握手”,即交换三个分组。大致流程如下:客户端向服务器发送一个syn j 服务器向客户端响应一个syn k,并对syn j进行确认ack j+1 客户端再想服务器发一个确认ack k+1 只有就完了三次握手,但是这个三次握手发生在socket的那几个函数中呢?如图:4.3.7、socket中tcp的四次握手释放连接详解上面介绍了socket中tcp的三次握手建立过程,及其涉及的socket函数。现在我们介绍socket中的四次握手释放连接的过程,请看下图:图示过程为:某个应用进程首先调用close主动关闭连接,这时tcp发送一个fin m;另一端接收到fin m之后,执行被动关闭,对这个fin进行确认。它的接收也作为文件结束符传递给应用进程,因为fin的接收意味着应用进程在相应的连接上再也接收不到额外数据;一段时间之后,接收到文件结束符的应用进程调用close关闭它的socket。这导致它的tcp也发送一个fin n;接收到这个fin的源发送端tcp对它进行确认。这样每个方向上都有一个fin和ack32第五章 linux下socket编程实现过程5.1 聊天室socket编译链接过程 1 监听链接利用socket,bind,listen建立链接,步骤是:(1) 先利用socket函数处事话socket端口,获得sock_fd(一种文件描述符)。sock_fd = socket(af_inet, sock_stream, 0), af_inet为ipv4协议,sock_stream为使用socket的流模式;(2) ip地址及其处理过程详见上一章。(3) 使用bind函数绑定端口及其ip地址。(4) 利用listen函数监听。 2 发送请求(1) 获取主机信息(2) 初始化socket端口(3) 利用connect函数讲自己的ip地址等信息发送到主机,等待主机接受信息。 3 主机接受请求通信开始(1) 主机利用accept接收请求(2) 创建子进程,显示出聊天室界面(3) 接收返回信息,显示链接成功,并退出链接。(4) 关闭客户端socket。4 详细流程图:5.1 具体操作(1)在linux的vi编辑器下编写服务器端程序servc和客户端程序clt.c。运用交叉编译工具arm-linux-gcc,执行编译指令生成可执行文件。其makefile指令为:cc := gcccflags += -w -g -o -o2 -o3 -orm := rm -rf *libs := -lpthreadall:$(cc) $(cflags) multithread_tcp_server multithread_tcp_server.c $(libs)$(cc) $(cflags) multithread_tcp_client multithread_tcp_client.c $(libs)clean:$(rm)执行编译命令为:编译没有错误则会生成可执行文件。(2)配置服务器和客户端的ip,保证网络畅通,在servc中已将服务器的ip设置为:192168138.141。在客户端的“网络设置”中设置ip为服务器相同网段,可以通过ping命令检测网络是否畅通。(3)在一台计算机的终端先运行服务器程序(./multithread_tcp_server -p 8080),再在客户端的计算机终端上运行客户端程序()就会看到结果;运行结果如下所示。服务器端:等待链接界面:链接成功界面:客户端:客户注册成功界面:通信过程:用户1和用户2相互通信界面:(在此图中同时显示了在线用户)每登陆一个用户,系统会自动注册,保存在user_list.c中,通信时只需指定用户,就可以实现多线程间通信。参考文献:1w.richard steven.tcp/ip 详解 卷1:协议tcp/ip iiiustrated volume 1: the protocols.2w.richard steven, bill fenner, andrew m.rudoff unix.网络编程卷1、卷2.3kurt wall. gnu/linux编程指南 .4严蔚敏,吴伟明.数据结构(c语言版). 5谭浩强.c语言程序设计.6kenneth a.reek.c和指针.7mendel cooper.linux shell编程从入门到精通.附录该附录主要显示的时,该系统的源代码:附录a: multithread_tcp_server.c#include common.h#include user_list.cuser_list head=null;void *start_routine(void *arg)/thread functionfd_set readfds;struct timeval ts;int newfd = *(int *)arg;int maxfd = newfd;int ret = -1;char buffer_rbuff_size;int rc = -1, wc = -1;while (running)select_label:maxfd = (maxfd newfd) ? maxfd : newfd);ts.tv_sec = 1;ts.tv_usec = 0;fd_zero(&readfds);fd_set(0, &readfds);fd_set(newfd, &readfds);ret = select(maxfd + 1, &readfds, null, null, &ts);if (ret = -1)if (errno = eintr)goto select_label;elseuser_list delet=delete_pointer(find_user(head,newfd), head);if(delet!=null)head=delet;send_list( head);close(newfd);err_sys(server select)/if (ret = -1)else if (ret = 0)/fprintf(stderr, server time outn);continue;else/*server read*/if (fd_isset(newfd, &readfds)memset(buffer_r, 0, buff_size);rc = recv(newfd, buffer_r, buff_size, 0);if (rc = -1)close(newfd);err_sys(server recv)else if (rc = 0)user_list delet=delete_pointer(find_user(head,newfd), head);if(delet!=null)head=delet;send_list(head);close(newfd);fd_clr(newfd, &readfds);err_sys(client is shut down)elsebuffer_rbuff_size - 1 = 0;forward(head,buffer_r,newfd);/if (fd_isset(newfd, &readfds)/select return value 0/while (running)close(newfd);pthread_exit(null);int main (int argc, char *argv)int sockfd = -1;socklen_t addrlen = addr_size;if (argc != 3)fprintf(stderr, usage:%s -p server_portn, argv0);exit(exit_failure);sockfd = socket(af_inet, sock_stream, 0);/closedif (sockfd = -1)err_sys(server socket) int i = 1;setsockopt(sockfd, sol_socket, so_reuseaddr, (void *)&i, sizeof(i);struct sockaddr_in server_addr;bzero(&server_addr, addr_size);server_addr.sin_family = af_inet;/ipv4server_addr.sin_addr.s_addr = htonl(inaddr_any);/inaddr_any server_addr.sin_port = htons(atoi(argv2);if (bind(sockfd, (struct sockaddr *)&server_addr, addrlen) = -1)close(sockfd);/shutdown(sockfd, shut_rd | shut_wr);err_sys(server bind)if (listen(sockfd, back_log) = -1)/closed-listenshutdown(sockfd, shut_rd | shut_wr);err_sys(server listen)int newfd = -1;struct sockaddr_in client_addr;pthread_t pt = -1;pthread_attr_t attr;int ret = -1;pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr, pthread_create_detached);pthread_attr_setscope(&attr, pthread_scope_system);int num=1;user_list next_p=null;while (running)printf(nparent process%d whose master thread is %u is waiting for a new connection.n, getpid(), pthread_self();if(head!=null)send_list( head);bzero(&client_addr, addr_size);newfd = accept(sockfd, (struct sockaddr *)&client_addr, &addrlen);if (newfd = -1)if (errno = eintr)continue;elseclose(sockfd);err_sys(server accept)elseprintf(create a new connection%d =client ip%s|client port%d=n, newfd, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port);if(head=null)next_p=creat_pointer();head=next_p;write_list(next_p,num,newfd,client_addr.sin_addr);elsenext_p=last_p(head);next_p-next=creat_pointer();next_p=next_p-next;write_list(next_p,num,newfd,client_addr.sin_addr);num+;/*create a new s

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论