找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4509|回复: 0
收起左侧

网络程序设计实验报告下载 UDP下socket编程

[复制链接]
ID:108615 发表于 2016-3-14 15:40 | 显示全部楼层 |阅读模式
网络程序设计实验报告
一、实验目的
1.熟悉UDP下socket编程,掌握socket编程的具体实现步骤
2.熟悉进程间通信方式,掌握常用IPC编程方法
3.熟悉并发服务器模型,掌握一种编程方法
二、实验内容
1.用UDP套接字实现流式通信
2.用管道,套接字,共享内存实现一个大文件的传输并比较他们的速率
3.创建一个TCP并发服务,并可支持断点续传。
三、实验步骤
1.用UDP套接字实现流式通信
基于UDP套接字的编程模型如下:              


0.png

其中,在服务器端,服务器创建socket描述符,并将该描述符邦定到本服务器地址上,接着调用接收函数recvfrom,如果此时客户端没有发来UDP请求,服务器一直阻塞在recvfrom函数。当服务器接收到客户端发来的UDP请求后,服务器端继续执行recvfrom函数之后的代码,处理客户端请求,处理完成后再通过sendto函数无阻塞地将处理结果返回到客户端,之后服务器端循环又回到recvfrom函数,等待客户端的UDP请求。
在客户端,用户创建socket描述符,并将该描述符邦定到指定的服务器地址上,接着调用发送函数sendto将客户端的请求通过UDP无阻塞地发送到服务器,接着执行到接收函数recvfrom,如果服务器还没有UDP请求发送到客户端,客户端一直阻塞在该函数。当服务器执行完客户端的请求,并把结果通过UDP发送到客户端后,客户端接收结果,最后客户端关闭socket端口,客户端与服务器的一次对话结束。

2.用管道,套接字,文件共享实现一个大文件的传输
(1)管道可以用于具有亲缘关系的进程间通信,命名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系的进程之间通信。当进程创建一个管道的时候,系统内核同时为该进程设立了一对文件句柄,一个用来从管道获取数据,另一个用来向管道输出数据,如图2-1。在主进程中利用fork()函数创建一个子进程,该子进程继承了父进程打开的文件句柄,利用继承的句柄,就可以实现父子进程之间的通信,如图2-2。
现在,父子两个进程同时拥有对同一个管道的读写句柄,因为管道必须是单向的,所以还需要决定数据的流动方向是从父进程到子进程还是从子进程到父进程,然后在每个进程中关闭不需要的句柄。假设需要利用管道完成从父进程向子进程传送数据,关闭了相应句柄后的管道如图2-3所示。

1.png

通过以上操作后,建立好像完整的管道数据通路,就可以利用标准的读写函数read()、write()对管道进行读写操作了。
在具体的C程序中,使用pipe()函数来建立管道。它只有一个参数:一个有两个成员的整形数组,用于存放pipe()函数新建立的管道句柄。
(2)套接字是两个通信通道上得端点。套接字函数可以用来产生通信信道,通过信道两个应用程序间可以传送数据。由于需要传输的是文件,所以选择安全机制较高的TCP套接字。基于TCP套接字的编程模型如下:


0.png


在服务器端,服务器创建socket描述符,将该描述符邦定到自己的IP地址上,再设置最大连接请队列长度,接着用accept接收请求函数等待客户端的请求,如果没有收到客户端的请求,服务器就阻塞在此。收到客户端请求后,服务器读取该请求,经过处理,最后将处理结果通过write写函数返回到客户端。
在客户端,用户程序创建socket描述符,并用connet连接函数将该描述符连接到服务器的地址上,连接上后客户端通过write写函数将请求发送到服务器,服务器经过处理将结果返回客户端,客户端通过read函数读取处理结果,当服务器没有结果返回时,客户端将一直阻塞在read函数。
(3)共享内存实现进程间通信,系统在内存中指定一个区域作为共享存储区域,建立一张表进行管理,各进程可以申请其中的一个存储段,并在申请时提供关键字。若申请的存储区已经被其他进程所有,则系统向申请进程返回关键字,该存储区就连接了进程的逻辑地址空间,此后进程就可以直接存取共享存储区中的数据了;若申请的存储段尚未分配,则系统会按照申请者的要求分配存储段,并在段表中加入该进程的信息。一个进程可以申请多个存储段,使用共享存储区进行通信时进程间的互斥或同步要靠其他的机构来解决。
在调试代码的时候发现用共享内存的方式传输一个5MB左右的文件的时候可以,但是传输100多MB的文件时,创建共享内存的函数shmget()返回报错。在网上搜也没有搜到合适的解答,后来偶然发现了shmmax这个参数,在往上搜索这个参数发现Linux对共享内存的大小有限制。后来找到了解决的办法,用echo 268435456 > /proc/sys/kernel/shmmax 指令临时把系统最大共享内存限制提高到256MB,之后再调试程序,发现大文件可以传输,问题解决。但随后又发现一个问题,在用共享内存方式传送小文件时速度很快,平均300MB/s左右。但在传送大文件时,速度比较慢,平均几十MB/s左右,对于该问题,我也没弄清是怎么回事。

3.创建一个TCP并发服务,支持断点续传
原本打算参考一个Linux下的基于命名行的开源Ftp客户端软件cmdftp,找的是比较原始的0.7.3版本,代码不多,不到3000行,但是自己阅读之后发下里面的命令解析过于复杂,而且应用层用的Ftp协议也比较庞大;找了开源的Ftp服务器端软件,发现异常庞大,在短时间内几乎不可能完成。所以最后采用了网上的一个基于MFC开发的Windows下的局域网文件传输工具。

四、实验结果
以上各个实验均在Fedora9下,使用Qt Creator开发环境调试通过,各个实验的结果截图如下:
1.用UDP套接字实现流式通信


image001.png
客户端程序运行情况
image002.png
服务器端程序运行情况
image003.png
QT4开发环境
2.用管道,套接字,文件共享实现一个大文件的传输
image004.png
管道传输
image005.png
QT4开发环境
image006.png
套接字传输客户端
image007.png
套接字传输服务器端
image008.png
QT4开发环境
image009.png
共享内存传输(小文件)
image010.png
共享内存传输(大文件)
可以看出,除了用共享内存传输大文件(这种情况下为何速度不高没有弄清楚)这种情况。传输速度依次为:
管道:42 MB/s
套接字:47 MB/s
共享内存:300 MB/s
无疑,共享内存速度最快,按照理论管道应该比套接字速度快,但本实验中发现套接字竟然比管道速度快,这个问题也没有弄清楚。
image011.png
QT4卡开发环境
3.创建一个TCP并发服务,支持断点续传
image012.jpg
服务器端传输程序界面
image013.jpg
客户端接收程序界面
五、实验总结
通过本次课程设计,初步了解了Linux下的网络程序设计的步骤,对基于套接字的编程有了个新的认识。Qt集成开发环境使Linux下的C/C++开发方便了许多,无论是代码编写还是调试运行。虽然没有独立完成最后一题,但也通过在尝试自己编写,自己阅读开源的小型Ftp客户端软件,对Linux的Shell编程有了新的认识,尤其对如何利用标准C编写跨平台程序。总体通过这次作业,收获到了很多以前不了解或了解不深入的东西,对网络程序设计有了新的认识。

下面是部分源码,完整代码请下载51黑的附件:
  1. #include
  2. #include
  3. #include
  4. #include
  5. #include
  6. #include
  7. #include
  8. #include
  9. #include

  10. int main(int argc, char ** argv)
  11. {
  12.     if(argc != 2)
  13.     {
  14.         printf("usage: udp_client portnum");
  15.         exit(1);
  16.     }
  17.     short port = atoi(argv[1]);
  18.     int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  19.     if(sockfd == -1)
  20.     {
  21.         printf("error create socket!");
  22.         exit(1);
  23.     }

  24.     struct sockaddr_in srvaddr;
  25.     srvaddr.sin_family = AF_INET;
  26.     srvaddr.sin_port = htons(port);
  27.     if(inet_aton("127.0.0.1", &srvaddr.sin_addr) == -1)
  28.     {
  29.         printf("error address convert!");
  30.         exit(1);
  31.     }

  32.     char buf[100];
  33.     struct timeval time;

  34.     while(1)
  35.     {
  36.         gettimeofday(&time, NULL);
  37.         sprintf(buf,"this is hello from client! %d",(int)time.tv_sec);
  38.         sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
  39.         sleep(1);
  40.     }

  41. }
复制代码
论文和程序下载:
0.png
网络程序设计报告 源码.rar (2.06 MB, 下载次数: 9)
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表