西电2015网络程序设计大作业_第1页
西电2015网络程序设计大作业_第2页
西电2015网络程序设计大作业_第3页
西电2015网络程序设计大作业_第4页
西电2015网络程序设计大作业_第5页
已阅读5页,还剩28页未读 继续免费阅读

下载本文档

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

文档简介

1、精选优质文档-倾情为你奉上西安电子科技大学网络程序设计实验报告班级: 姓名: 学号: 专心-专注-专业实验一:1. linux平台上的TCP并发服务一、实验内容掌握基本套接字函数使用方法、TCP 协议工作原理、并发服务原理和编程方法。实验内容:在 linux 平台上实现 1 个 TCP 并发服务器,至少可以为 10 个客户端同时提供服务。(1) 基于 TCP 套接字编写服务器端程序代码,然后编译和调试;(2) 服务器程序要达到:可以绑定从终端输入的 IP 地址和端口;可以显示每一个进程的进程号;可以显示当前并发执行的进程数量;可以根据客户机要求的服务时间确定进程的生存时间。(3) 基于 TCP

2、 套接字编写客户端程序代码,然后编译和调试;(4) 客户端程序要达到:可以从终端输入服务器的 IP 地址和端口;可以从终端输入对服务器的服务时间要求。(5) 联调服务器和客户端,服务器每收到一个连接就新建一个子进程,在子进程中接收客户端的服务时间请求,根据所请求的时间进行延时,然后终止子进程。如:客户端请求服务 10s,则服务器的子进程运行 10s,然后结束。(6) 服务器要清除因并发服务而产生的僵尸进程。二、分析及设计要实现并发的服务器,也就是要求在同一段时间内,服务器能处理多个不同的客户端的请求,并且要区分出它们各自差别,然后做到区别对待这里只要用各自的进程的fd来区分各自的身份。不过这里

3、因为水平有限,没有实现各个客户端各自定一个服务时间,服务时间是按照客户端连接到退出的这段时间,也就是要客户端主动退出。三、详细实现服务器端:负责接收客户端的信息,然后在区分各个客户端的前提下,将信息复述出来。以下是各种参数的初始定义;生成服务端进程套接字及初始化;调用bind()和listen()函数来绑定套接字地址和句柄以及坚挺服务请求;select()函数可以设置超时,是长期没有文件描述符就绪时,进程可以跳出阻塞状态;之后的各种情况跳转判断,请看附录的详细代码客户端:各种参数以及初始化,因为客户端逻辑功能较少,因此参数的个数也不及服务器端的多;调用connect()函数,将该套接字和服务器

4、套接字相连接;从命令行读入信息;其余代码见附录。四、实验结果实验二:进程间的协调通信一、实验内容掌握进程的概念、进程间通信的基本原理、集成间通信的主要类型和各自的特点。实验内容:在 linux 平台上实现 1 个父进程、2 个子进程,利用管道和共享内存实现两个子进程之间数据快速传送。(1) 创建一个进程,再创建一对管道、一块共享内存(大于 64kB);(2) 通过 fork()函数生成 2 个子进程;(3) 调试程序,确定父、子进程之间可以双向通信;(4) 调试程序,确定两个子进程之间可以通过父进程中转实现双向通信;(5) 调试程序,确定两个子进程都可访问共享内存;(6) 实现两个子进程之间无

5、冲突地访问共享内存。传送的数据块不小于 32kB,为了能够看到演示效果,读/写每个字节后都延时 0.5ms。二、分析及设计管道:管道又可以分为无名管道和命名管道,两者的用途是不一样的。无名管道 PIPE:主要用于具有亲缘关系的进程之间的通信,无名管道的通信是单向的,只能由一段到另外一段; 无名管道是临时性的,完成通信后将自动消失。一般采用先创建无名管道,再创建子进程, 使子进程继承父进程的管道文件描述符,从而实现父子进程间的通信;在非亲缘关系管道之间,如果想利用无名管道进行通信,则需要借助另外的文件描述符传递机制。有名管道 FIFO:有名管道是一个实际存在的特殊文件,利用有名管道可以实现同主机

6、任意进程之间的数据交互。这里只需要无名管道,它只能在父子进程间传递信息,因此要求在两个子进程之间通信, 必须以父进程为媒介,进程 1 将信息传给父类,然后由父类将信息传给进程 2,以此来完成两子进程的一次通信。共享内存:通常由一个进程创建,其余进程对这块内存区进行读写。得到共享内存有两种方式: 映射/dev/mem 设备和内存映像文件。前一种方式不给系统带来额外的开销,但在现实中并不常用,因为它控制存取的是实际的物理内存;常用的方式是通过 shmXXX 函数族来实现共享内存:如果一个进程通过 fork 创建了子进程,则子进程继承父进程的共享内存,既而可以直接对共享内存使用,不过子进程可以自身脱

7、离共享内存。基于共享内存的通信,不需要父进程的帮助,只要将两个子进程与申请的进程块联系起来即可;主要的问题是两个子进程之间访问共享内存的互斥问题,必须等进程 1 写完内存后,进程 2 才能读取,顺序不能乱。这里其实又设计到了进程通信的另一种方式信号量,不过这不是重点,因此只采用了最简单的方式,设置一把锁,然后两个子进程循环检查这个标志锁,然后根据锁来决定是否就可以实现这个功能。以下是共享内存的原理示意图:三、详细实现管道:调用 pipe()来生成管道:调用 fork()创建一个子进程,并实现数据写入到父进程中:其余代码略;共享内存:定义一个结构体:创建一个共享内存并且将之连接到当前进程的地址空

8、间:一个进程负责内存写入:(读进程类似)Process_Write()和Process_Read()代码偏长,详见附录;四、实验结果管道:共享内存:其实可以看到进程间运行还是有些问题,You wrote多次出现。这个问题需要跟完善的信号操作来实现完全的按序执行。实验三:Windows平台上的TCP并发服务一、实验内容编程内容与实验1相同,操作系统为windows。了解Windows与Linux平台编程环境的差异,掌握Winsock编程接口及编程方法。二、分析及设计Berkeley套接字刚开始时4.2BSD Unix操作系统(与1983年发布)的一套应用程序接口, 设计之初就是为了实现TCP/I

9、P协议。Berkeley套接字应用程序接口形成了事实上的网络套接字的标准。而微软当时为了迅速占据市场以及招聘人才,全盘套用了Unix的网络编程实现,其中就包括了Berkeley套接字。不过由于Unix和Windows的内核实现是有差别的,Berkeley套接字在Windows上的运行效率并不高,因此后来Windows推出了Winsock,并且为了预防AT&T 申请专利,它被实现为一个与网络协议无关的网络编程接口。Winsock的实现一般在Berkeley套接字函数上加了前缀WSA用以区分。这个实验的具体实现其实和实验1没有实质上的区别,差别在于同样的功能要用不同的函数来实现。这个程序实

10、现的比较简单,服务器和客户端只有一次交换信息。三、具体实现(具体阐述与linux的异同) 服务器端:windwows下的socket编程函数库:各个参数及初始化:不同之处:同样是bind(),listen():其余代码略;客户端:connect()函数:使用完函数库,需要释放:四、实现结果心得体会:网络程序设计这门课是一门非常非常实用的课,可惜开课的时间不太合适,刚开始时, 网络方面的知识实在是非常的欠缺,因此现在看来非常基础的socket,在那时是根本无法理解的,而后来随着课程的推进,各种实验上机接踵而来,也无法抽出时间来好好学习网络编程,浪费了很多时间,这让我感到很可惜,错过了学习这门课的

11、最好时候。不过在这一段时间的补充学习,我还是追回来一点内容,至少不是两眼一蒙,不会啥都不认识了。Winsock的内容继承了Windows编程的一贯特点,艰涩难懂至少对于还没入门的我是这种感觉的。强烈希望能够网络程序这门课放到大三下学期!附录:实 验 一 : 服务器端:#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/time.h> #include <sys/types.h> #include <sys/socket.h> #i

12、nclude <netinet/in.h> #include <sys/select.h> #include <errno.h>#define SERVER_IP "127.0.0.1"#define SERVER_PORT 8000#define MAX_RECV_LEN 1024/发送信息的最大长度#define MAX_CLIENT_NUM 30/并发数量#define BACK_LOG 20/等待队列static int running = 1;int main(int argc, char *argv)int sock_fd =

13、 -1;/套接字文件描述符int ret = -1;struct sockaddr_in serv_addr; /服务器地址struct sockaddr_in cli_addr; /客户端地址socklen_t serv_addr_len = 0;socklen_t cli_addr_len = 0;int client_fdMAX_CLIENT_NUM; /客户端队列,用于区分各个客户端,并区分服务char recv_bufMAX_RECV_LEN;/缓冲区int new_conn_fd = -1;/新进程的fd int i = 0;int max_fd = -1; int num = -

14、1;struct timeval timeout;fd_set read_set; fd_set write_set; fd_set select_read_set;FD_ZERO(&read_set); FD_ZERO(&write_set); FD_ZERO(&select_read_set);for (i = 0; i < MAX_CLIENT_NUM; i+)client_fdi = -1;/初始化memset(&serv_addr, 0, sizeof(serv_addr);/初始化memset(&cli_addr, 0, sizeof(

15、cli_addr);sock_fd = socket(AF_INET, SOCK_STREAM, 0); /生成TCP/IP协议的套接字if (sock_fd < 0)perror("Fail to socket");/套接字生成失败exit(1);serv_addr.sin_family = AF_INET;/TCP/IP协议族serv_addr.sin_port = htons(SERVER_PORT);/ 端 口 号 ,8000 serv_addr.sin_addr.s_addr = inet_addr(SERVER_IP);/格式化(本地)IP地址unsign

16、ed int value = 1;if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&value, sizeof(value) < 0)perror("Fail to setsockopt"); exit(1);serv_addr_len = sizeof(serv_addr);if (bind(sock_fd, (struct sockaddr*)&serv_addr, serv_addr_len) < 0)/绑定套接字地址和句柄perror("Fail to bind

17、"); exit(1);if (listen(sock_fd, BACK_LOG) < 0)/调用listen()perror("Fail to listen"); exit(1);char buf1024; max_fd = sock_fd; int len;FD_SET(sock_fd, &read_set); while (running)timeout.tv_sec = 5;/等待时间timeout.tv_usec = 0;max_fd = sock_fd;for (i = 0; i < MAX_CLIENT_NUM; i+)if (m

18、ax_fd < client_fdi)max_fd = client_fdi;select_read_set = read_set;ret = select(max_fd + 1, &select_read_set, NULL, NULL, &timeout);/设置超时,/当长期没有文件描述符就绪时,跳出阻塞状态if (ret = 0)/队列为空printf("timeoutn");else if (ret < 0)/ 出错printf("error occurn");elseif (FD_ISSET(sock_fd, &a

19、mp;select_read_set)printf("new client comesn"); len = sizeof(cli_addr);new_conn_fd = accept(sock_fd, (struct sockaddr*)&cli_addr, &len); if (new_conn_fd < 0)perror("Fail to accept"); exit(1);elsefor (i = 0; i < MAX_CLIENT_NUM; i+)if (client_fdi = -1)client_fdi = new

20、_conn_fd; FD_SET(new_conn_fd, &read_set);break;if (max_fd < new_conn_fd)max_fd = new_conn_fd;elsefor (i = 0; i < MAX_CLIENT_NUM; i+)memset(recv_buf, 0, MAX_RECV_LEN);if (FD_ISSET(client_fdi, &select_read_set)num = read(client_fdi, recv_buf, MAX_RECV_LEN); if (num < 0)printf("Cl

21、ient(%d) leftn", client_fdi); FD_CLR(client_fdi, &read_set); close(client_fdi);client_fdi = -1;else if (num > 0)recv_bufnum = '0'printf("Recieve client(%d) datan", client_fdi);/输出服务器fdprintf("Data:%snn",recv_buf);/输出信息 if (num = 0)printf("Client(%d) exitn

22、", client_fdi); FD_CLR(client_fdi, &read_set); close(client_fdi);client_fdi = -1;return 0;客户端:#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/time.h> #include <sys/types.h> #include <sys/socket.h> #includ

23、e <netinet/in.h> #include <sys/select.h>#define SERVER_IP "127.0.0.1"#define SERVER_PORT 8000#define MAX_RECV_LEN 1024static int running = 1;int main(int argc, char *argv)int sock_fd = -1; int ret = -1;struct sockaddr_in serv_addr; struct sockaddr_in cli_addr; socklen_t serv_ad

24、dr_len = 0;memset(&serv_addr, 0, sizeof(serv_addr);sock_fd = socket(AF_INET, SOCK_STREAM, 0); if (sock_fd < 0)perror("Fail to socket"); exit(1);serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(SERVER_PORT); serv_addr.sin_addr.s_addr = inet_addr(SERVER_IP);serv_addr_len = s

25、izeof(serv_addr);if (connect(sock_fd, (struct sockaddr *)&serv_addr, serv_addr_len) < 0)/与服务器套接字相连接perror("Fail to connect"); exit(1);char buf1024; int num = 0; while (running)num = read(STDIN_FILENO, buf, MAX_RECV_LEN); if (num > 0)bufnum = '0'printf("buf: %sn"

26、, buf);num = write(sock_fd, buf, num); if (num < 0)printf("write failedn"); exit(1);if (strncmp(buf, "exit", strlen("exit") = 0)printf("Client exitn"); close(sock_fd);return 0;return 0;实验二: 管道:#include<stdio.h> #include<unistd.h> #include<str

27、ing.h>int main()int p12,p22;/两个管道int pid1,pid2;/用于区分两个进程char *str = "HelloWorld"char buf1128,buf2128; /缓冲区memset(buf1,'0',128); / 初 始 化memset(buf2,'0',128);if(pipe(p1) = -1) / 生 成 管 道printf("function pipe() calls failed."); return -1;if(pipe(p2) = -1)printf(&qu

28、ot;function pipe() calls failed."); return -1;if(pid1=fork() = -1)/创建一个子进程printf("function fork() calls failed.n"); return -1;else if(pid1 = 0)/在子进程1中printf("In child1 : pid=%dn",getpid(); write(p11,str,strlen(str); /向无名管道中写入strelse /在父进程中printf("In father : pid=%dn&quo

29、t;,getpid(); read(p10,buf1,strlen(str);/读取无名管道printf("In father : buf=%sn",buf1); write(p21,buf1,strlen(str);if(pid2=fork() = -1)/创建一个子进程printf("function fork() calls failed.n"); return -1;else if(pid2 = 0)/在子进程2中read(p20,buf2,strlen(str);printf("In child2 : pid=%dn",ge

30、tpid(); printf("In child2 : buf=%sn",buf2);共 享 内 存 : #include <unistd.h> #include <stdlib.h> #include <stdio.h>#include <sys/ipc.h> #include <sys/shm.h>#define TEXT_SZ 1024/缓存区大小void *shm = NULL;/分配的共享内存的原始首地址struct shared_use_st *shared =NULL;int shmid;/共享内存标

31、识符struct shared_use_stint written;/作为一个标志,1表示可读,0表示可写char textTEXT_SZ;/记录写入和读取的文本;int main()int pid1,pid2;/创建共享内存shmid = shmget(key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT); if(shmid = -1)fprintf(stderr, "shmget failedn"); exit(EXIT_FAILURE);/将共享内存连接到当前进程的地址空间shm = shmat(shmid

32、, 0, 0);shared = (struct shared_use_st*)shm; shared->written = 0;printf("nMemory attached at %Xn", (int)shm); pid1 = fork();/写进程if(pid1 = 0)if(shm = (void*)-1)fprintf(stderr, "shmat failedn"); exit(EXIT_FAILURE);Process_Write();pid2 = fork();/读进程if(pid2 = 0)if(shm = (void*)-1)

33、fprintf(stderr, "shmat failedn"); exit(EXIT_FAILURE);Process_Read();return 0;void Process_Read()while(1)/读取共享内存中的数据/没有进程向共享内存定数据有数据可读取if(shared->written != 0)printf("You wrote: %s", shared->text); sleep(rand() % 3);/读取完数据,设置written使共享内存段可写shared->written = 0;/输入了end,退出循环

34、(程序) if(strncmp(shared->text, "end", 3) = 0)break;else/有其他进程在写数据,不能读取数据sleep(1);/把共享内存从当前进程中分离if(shmdt(shm) = -1)fprintf(stderr, "shmdt failedn"); exit(EXIT_FAILURE);/删除共享内存if(shmctl(shmid, IPC_RMID, 0) = -1)fprintf(stderr, "shmctl(IPC_RMID) failedn");exit(EXIT_FAILU

35、RE); exit(EXIT_SUCCESS);void Process_Write()/设置共享内存char bufferBUFSIZ + 1;/用于保存输入的文本while(1)/向共享内存中写数据/数据还没有被读取,则等待数据被读取,不能向共享内存中写入文本while(shared->written = 1)sleep(1); printf("Waiting.n");/向共享内存中写入数据sleep(2);printf("Enter some text: "); fgets(buffer, BUFSIZ, stdin); strncpy(sh

36、ared->text, buffer, TEXT_SZ);/写完数据,设置written使共享内存段可读shared->written = 1;/输入了end,退出循环(程序) if(strncmp(buffer, "end", 3) = 0)break;/把共享内存从当前进程中分离if(shmdt(shm) = -1)fprintf(stderr, "shmdt failedn"); exit(EXIT_FAILURE);sleep(2); exit(EXIT_SUCCESS);实 验 三 : 服务器端:#include <iostr

37、eam> #include <stdio.h>#include <windows.h>/一定要包含该头文件using namespace std;#pragma comment(lib, "WS2_32.lib") /windwows下的socket编程函数库int main()WSADATA wsaData;WORD sockVersion = MAKEWORD(2, 2);/windows网络编程库的版本号信息,最新是2.2 SOCKET sListen = 0;/TCP通信的socket数据结构sockaddr_in sin = 0 ;/

38、创建一个socket编程类型的网络地址数据结构这个用于本地sockaddr_in remoteAddr = 0 ;/创建一个socket编程类型的网络地址数据结构这个用于储存远程主机的/IP地址和端口号char szText = "TCP Server Demo" int nAddrLen = 0;nAddrLen = sizeof(sockaddr_in);/计算这个sockaddr_in数据结构的大小/fill sinsin.sin_port = htons(4567);/设置本地(这里指服务端)计算机要打开的端口sin.sin_family = AF_INET;/设置

39、网络通信的网络协议族类型sin.sin_addr.S_un.S_addr = INADDR_ANY;/设置本地计算机的IP地址,一般INADDR_ANY在程序运行时/会自动计算成本地的IP地址的/init wsaif (WSAStartup(sockVersion, &wsaData) != 0)/WSAStartup函数是在程序中初始化并加载Windows网络/编程库的ws2_32.dll动态库文件。cout << "initlization failed!" << endl;exit(0);/如果WSAStartup返回值为1的话就表示w

40、s2_32.dll文件有问题,程序退出sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); /在本机上创建一个socket/使用bind函数绑定本机的ip和打开端口到本机创建的socket结构上,并初始化该socket/重点说明一个在服务器上是用bind函数来初始化socket,在客户机上是用connect函数来 初始化socket的喔if (bind(sListen, (LPSOCKADDR)&sin, sizeof(sin) = SOCKET_ERROR)cout << "bind failed!"

41、 << endl;return 0;/如果socket绑定失败返回程序0并退出程序if (listen(sListen, 2) = SOCKET_ERROR) /listen是用来打开本地计算机的端口,参数2表示客户端同/时连接服务器的数量,这里是说可以同时有2个客户端连接/到本机打开的端口cout << "listen failed!" << endl;return 0;/如果打开本地端口失败就返回0并退出程序SOCKET sClient = INADDR_ANY;/再服务器上再创建一个socket结构,用来储存与一个客户端进行通信连/

42、接的连接实例int num = 0; while (true)/accept函数是用来创建一个TCP通信连接实例的,他使用一个远程计算机的IP地址和 本地计算机上创建的一个/socket,这两个信息来创建一个本地计算机到远程计算机的一个TCP通信连接实例的socket,sClient就是当前/程序中的这个连接实例的socket 了。注accept函数也可以直接理解为接受一个客户机的连接请求。sClient = accept(sListen, (SOCKADDR*)&remoteAddr, &nAddrLen);if (sClient = INVALID_SOCKET)听状态co

43、ut << "accept failed!" << endl;continue;/如果本地计算机(服务器)接受一个客户端连接请求失败就退出监elsenum+;cout <<"NO."<<num<< " accept successed!" << endl;/send函数是在TCP连接建立之后,就来发送数据的。其中sClient是存放有一个连接 实例的socket结构来/的。这个服务器上的send函数的socket参数和客户机上的socket参数是不同的喔, 记住这

44、里的socket参数是通过/accept函数创建的喔。不是用connet函数和bind函数创建喔。一定要记住这个sClient是一个关键来的。然后/szText就是我们想要发送的数据了。这里我们向连接到该服务器的客户端发送了一个“TCP Server Demo”的信息。send(sClient, szText, strlen(szText), 0);closesocket(sClient);/关闭这个用accept函数建立socket对象,关闭与remoteAddr连接通信。/remoteAddr这结构理包含了有远程计算机的IP和端口号信息,当客户机/使用connect函数发送一个连接请求时,被accept函数接受并处理后,远/程计算机的IP地址和端口信息就被填到了remoteAddr这个结构中去/了。closesocket(sListen);/关闭本地计算机(服务器)上的由bind函数创建的socket对象, 关闭本机/ 打 开 的 端 口 , 关 闭 服 务 器 WSACle

温馨提示

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

评论

0/150

提交评论