已阅读5页,还剩13页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
计算机网络实验 题目:Socket 编程 实验 1 基于 UDP 的 Socket 编程 实验 2 基于 TCP 的 Socket 编程 姓名: 学号: 学院: 年级: 实验时间: 目录 一、实验内容: 3 实验 1 基于 UDP 的 Socket 编程 3 实验 2 基于 TCP 的 Socket 编程 3 二、 程序设计 3 1 基于 UDP 的 Socket 编程 .3 1.1 实验原理:基于 UDP 协议的无连接 C/S 的工作流程 .3 1.2 实现方案和实验结果 .4 1.2.1 方案 1:Linux 上两个进程间的通信 4 方案 1 实现方案 4 方案 1 实验结果 4 1.2.2 方案 2:Windows 主机( client)和 Linux 虚拟机(server)之间的进程通信 6 方案 2 实现方案 6 方案 2 实验结果 6 2 基于 TCP 的 Socket 编程 .7 2.1 实验原理:基于 TCP 协议的面向 C/S 的工作流程 .7 2.2 实现方案 .8 2.3 实验结果 .9 三、讨论与心得 10 四、源代码 12 一、实验内容: 本单元实验包括的实验项目主要是 UDP Socket 编程和 TCP Socket 编程。本单元实验 的主要目的是希望通过本单元实验,让学员掌握 Socket 编程方法,同时通过本单元实验让 学生掌握如何开发基于 TCP/IP 协议的网络应用。 实验 1 基于 UDP 的 Socket 编程 实验目的:通过本实验使学员了解和掌握编写基于 UDP 协议的网络应用程序。 实验内容:编写基于 UDP 协议网络聊天程序,要求发送程序和接收程序能够接收键盘 输入并彼此之间相互发送数据。 实验步骤: 1.编写 server 端程序; 2.编写 client 端程序; 3.client 程序与 server 程序联调; 4.client 程序与 server 程序相互通信。 实验 2 基于 TCP 的 Socket 编程 实验目的:通过本实验使学员了解和掌握编写基于 TCP 协议的网络应用程序。 实验内容:编写基于 TCP 协议网络聊天程序,要求发送程序和接收程序能够接收键盘 输入并彼此之间相互发送数据。 实验步骤同 UDP 实验。 2、程序设计 1 基于 UDP 的 Socket 编程 1.1 实验原理:基于 UDP 协议的无连接 C/S 的工作流程 在 server 端,server 首先启动,调用 socket( )创建套接字,然后调用 bind( )绑定 server 的地址(IP+port) ,调用 recvfrom( )等待接收数据。 在 client 端,先调用 socket()创建套接字,调用 sendto( )向 server 发送数据。 server 接收到 client 发来数据后,调用 sendto( )向 client 发送应答数据,client 调用 recv 接收 server 发来的应答数据。数据传输结束,server 和 client 通过调用 close( )关闭套接字。 原理图如图 1。 图 1 UDP 通信原理图 1.2 实现方案和实验结果 1.2.1 方案 1:Linux 上两个进程间的通信 方案 1 实现方案 server 端: 首先调用 socket 函数创建一个 socket,然后调用 bind 函数将其与本机地址以及一个本地端 口号绑定,用 recvfrom 函数接收到一个 client 端的消息后,用 printf 打印出来,server 从标 准输入设备中取得一行字符串后,调用 sendto 函数发送给 client 端。最后用 close 关闭该 socket。 client 机端: 首先调用 socket 函数创建一个 socket,初始化 server 地址及端口号(实际上就是本机) ,从 标准输入设备中取得字符串,用 sendto 传送给 server 端,然后用 recv 函数接收 server 端发 来的字符串,用 printf 打印出来。最后用 close 关闭该 socket。 源代码见附录。 方案 1 实验结果 server 和 client 通信截图 图 2 UDPserver 图 3 UDPClient 1.2.2 方案 2:Windows 主机( client)和 Linux 虚拟机 (server)之间的进程通信 方案 2 实现方案 利用 Vmware station 的 Linux 虚拟机与 Windows 本机之间的局域网进行进程间通信, Linux 虚拟机作为 server,Windows 本机作为 client。除了 Windows 使用 winsock 函数库之 外,实现方案与方案 1 类似,但要注意 client 端初始化的 server 地址虽然与方案 1 相同, 但此时已不再是本机地址,而是局域网中 Linux 虚拟机的 IP 地址,相当于模拟了不同机器 间的进程通信。 方案 2 实验结果 server 和 client 通信截图 图 4 server 图 5 client 2 基于 TCP 的 Socket 编程 2.1 实验原理:基于 TCP 协议的面向 C/S 的工作流程 在 server 端,server 首先启动,调用 socket( )创建套接字;然后调用 bind( ) 绑定 server 的地址(IP+port ) ;再调用 listen( )让 server 做好侦听准备,并规定好请求队列长度,然后 server 进入阻塞状态,等待 client 的连接请求;最后通过 accept( )来接收连接请求,并获得 client 的地址。当 accpet 接收到一个 client 发来的 connet 请求时,将生成一个新的 socket, 用于传输数据。 在 client 端,client 在创建套接字并指定 client 的 socket 地址,然后就调用 connect( )和 server 建立连接。一旦连接建立成功,client 和 server 之间就可以通过调用 recv 和 send 来 接收和发送数据。一旦数据传输结束,server 和 client 通过调用 close( )来关闭套接字。 原理图如图 6。 图 6 2.2 实现方案 server 端: 首先调用 socket 函数创建一个 Socket,然后调用 bind 函数将其与本机地址以及一个本地端 口号绑定,然后调用 listen 在相应的 socket 上监听 client,当 accpet 接收到一个 client 发来 的 connet 请求时,将生成一个新的 socket,用于传输数据。Recv( )接收到一个 client 端的 消息后,server 从标准输入设备中取得一行字符串,调用 send()发送给 client 端。 client 端: 首先调用 socket 函数创建一个 Socket,初始化 server 地址及端口号,然后调用 connet 请求 连接监听 server。通过 server 端 accept 函数生成的新 socket,调用 send 函数向 server 端发 送从标准输入设备中取得的字符串,然后用 recv 接收 server 端发来的字符串。最后用 close()关闭该数据传输 socket 和监听 socket。 源代码见附录。 2.3 实验结果 server 和 client 通信截图 图 7 TCPserver 图 8 TCPserver 三、讨论与心得 记得助教第一节课讲 socket 的时候,我听得云里雾里的,只觉得是个很神奇的可以实 现进程间通信的类似于接口的东西。印象深刻的是他举的那个打电话的例子,描述得很直 观形象。老师说让我们做这个实验主要是为了体会 TCP/IP 的原理,并不要求应用做得多么 高端,比如图形界面什么的。我觉得,我既然是网络工程专业的,就更应该学好计算机网 络这门课,更好地了解 socket 编程。抱着这种决心,我开始了学习。 于是我先去网上找了有关 socket 编程的讲解,觉得一篇一切皆 socket的帖子写得 很易懂,对于各个函数的功能有了初步的了解。操作系统的课程也有一个做 shell 命令解释 器的实验,与 socket 编程实验基本是先后进行的。在做了 shell,熟悉了“一切皆文件”的 linux 以及编译、运行的方法之后,感觉跟好理解,更好入手了。 我先对照着一切皆 socket的帖子看老师给的资料附录一中的示例一、二,也就是 TCP。原来 socket()是用来创建一个,然后返回值是这个 socket 的描述符,很类似与文件描 述符。bind()是用来为这个 socket 绑定 server 的 IP+port 地址,当然绑定之前要先对 server 的地址进行初始化。listen()的作用是监听 client 的请求,第二个参数规定了这个刚刚创建 的 socket 可以接受几个 client 的服务请求。一旦 accept()了一个 client 的请求,就获得了这 个 client 的地址,这真是个很神奇的东东啊!操作系统就会又给它分配了一个 socket,也就 是 accept 的返回值,用来传输数据。也就是说, TCP 开了 2 个 socket,一个用来监听子进 程,一个用来传输数据。accept 之后就可以自由发挥,开始进行网络 I/0 了!我们运行程序 时可以看到的功能就是在下面的部分实现的。再往下的收发函数,read()/write() ,recv() /send(), readv()/writev(),recvfrom()/sendto() ,recvmsg()/sendmsg()什么的,就是用数据传输 的 socket 了,而非监听的 socket 了。关于收发函数,我又上网查了一下资料。拿 recv() /send()举例,其实 recv 只是把 TCP 协议传过来的数据 copy 到我们自己定义的 buf 里去。 而 recv 所做的把发送缓冲区里的数据被协议发送到接收缓冲区这个过程对于编程用户来讲 是不可见的,而 recv 只是把接收缓冲区里的数据 copy 出来而已。Send 与之类似。从这个 层面上讲,socket 是一个 TCP 协议提供的接口服务,用传输层的协议干应用层想干的事。 最后不要忘记用 close()关掉创建的两个 socket。此外,我大概理解了 TCP 的三次握手在函 数中的体现,要传三个报文,如图 1。 图 9 TCP 的三次握手建立连接 看懂、理解了代码后,我把代码拷了进去,调试成功后,看到了 server 会把 client 发 过来的数据再返回去,我觉得这个没什么意义,就想改编它,让 server 也可以通过输入回 答 client。于是就又定义了一个 buf3,用 gets 函数接受标准输入到 buf3 里,然后用把 buf3 的内容发给 client。 一个偶然的发现让我理解了 TCP 所谓的四次握手释放过程。当我把 client 关掉时, server 就自动关掉了。当 client 首先调用 close 主动关闭连接,这时 TCP 发送一个 FIN M; 另一端接收到 FIN M 之后,执行被动关闭,对这个 FIN 进行确认。它的接收也作为文件结 束符传递给 server 的应用程序,因为 FIN 的接收意味着 server 的应用进程在相应的连接上 再也接收不到额外数据;一段时间之后,server 上接收到文件结束符的应用进程调用 close 关闭它的 socket。这导致它的 TCP 也发送一个 FIN N;接收到这个 FIN 的源发送端 TCP 对 它进行确认。这样每个方向上都有一个 FIN 和 ACK。 图 10 socket 中发送的 TCP 四次握手释放 调通了 TCP 之后,我去尝试 UDP。其实这顺序是反了的,因为 UDP 貌似更简单一些, 可是因为 TCP 有现成的代码,所以就先理解了 TCP。之后去查 UDP 的资料,直观上感觉 除了创建 socket()时定义的协议不同外,就是少了一些函数,少用了一个 socket。对于 server 来讲,bind()之后,不用再 listen 和 accept 了,就是不用监听了,直接用这个 socket 来进行数据传输就可以了。于是我就想当然地觉得下面进行网络 I/O 的收发函数应 该是差不多的,就直接用了刚才在 TCP 里用的 recv 和 send。对于 client 来讲,我也是直接 用的这两个函数。然后怎么都传不了数据,实现不了通信。于是我仔细比较了几个函数的 参数,发现 recvfrom 比 recv 多了 2 个参数,后来理解了一下,这是因为 TCP 在 accept 时 就为与之通信的每个进程分配了一个 socket 用于数据传输,也就是说对于 server 的每个 client 都有一个专门的进程与其进行通信。而 UDP 没有开另外的进程,也就是没有创建新 的 socket,所以 server 的多个 client 是共用这一个 socket 的,可以说是多路复用了。为了辨 别多个 client, server 需要 client 的地址(ip+port )来接受和发送,于是就要用 recvfrom 多 出来的 2 个参数,即 client 的地址和地址长度。这也就同时解释了为什么 UDP 只创建一个 socket 就够了。对于 UDP 的 client 端来说,只需要在发送数据的时候用 sendto 来表明 server 的地址,在接收数据时就不需要的了,因为只有一个 server,不需要标记了。 因为我是在虚拟机上进行的以上实验,我就想利用主机和虚拟机之间的局域网来建立 连接,进行进程通信。虽然操作系统不同,socket 库不同,但是只要使用了相同的协议 (我选择的是 UDP)就可以进行通信。于是我又去学习了 Winsock 的相关知识,实现了不 同系统间的通信。我觉得虽然 Windows 和 Linux 的 socket 使用总体上差不多,但是 Winsock 的一些准备(我觉得比较冗余)复杂一点。 四、源代码 【UDP 方案 1】 Server 端源码: /udpService: #include #include #include #include #include #include #include #include #include #include #define PORT 7000 int main(void) int sockfd,pktlen; char buf300,buf1300; struct sockaddr_in server,client; sockfd=socket(AF_INET,SOCK_DGRAM,0); memset (char *) /将已开辟内存空间 server 的全部字节的值 设为值 0.类似于 bzero server.sin_family = AF_INET; server.sin_port = htons(PORT);/端口号 server.sin_addr.s_addr = INADDR_ANY;/设置网络地址,INADDR_ANY 表示机器的 IP 地址 bind(sockfd,(struct sockaddr *) for (;) /*recv 接受 client 发送的数据,recv 函数仅仅是 copy 数据,真正的接收数据是协议来完成的) , 第一个参数指定接收端套接字描述符;第二个参数指明一个缓冲区,该缓冲区用来存放 recv 函数接收到的数据;第三个参数指明 buf 的长度 recv 函数返回其实际 copy 的字节数 */ int l=sizeof(struct sockaddr_in); pktlen = recvfrom (sockfd, buf, sizeof (buf), 0,(struct sockaddr_in *) if (pktlen = 0) break; printf (“Received line: %sn“, buf); printf (“Enter a line: “); fgets(buf1,300,stdin); /*并不是 send 把 ns 的发送缓冲中的数据传到连接的另一端的,而是协议传的,send 仅仅 是把 buf 中的数据 copy 到 ns 的发送缓冲区的剩余空间里 返回实际 copy 的字节数*/ sendto (sockfd, buf1,sizeof(buf1), 0,(struct sockaddr_in*) close(sockfd); Client 端源码: /udpClient: #include #include #include #include #include #include #include #include #include #define MAX_SIZE 1024 #define PORT 7000 #define HOST_ADDR “192.168.145.137“ int main(int argc,char *argv) int sockfd,buflen; char buf1300,buf2300; struct sockaddr_in server; sockfd=socket(AF_INET,SOCK_DGRAM,0); server.sin_family=AF_INET; server.sin_port = htons(PORT); server.sin_addr.s_addr = inet_addr (HOST_ADDR); for(;) printf (“Enter a line: “); gets (buf1);/从 stdin 流中读取字符串,直至接受到换行符 buflen = strlen (buf1); if (buflen = 0) break; sendto(sockfd, buf1, buflen + 1, 0,(struct sockaddr *) recv(sockfd, buf2, sizeof (buf2), 0); printf(“Received line: %sn“, buf2); close(sockfd); return 0; 【UDP 方案 2】 Linux server 端源码同方案 1 Windows client 端源码: /客户端 #include #include #define INVALID_VALUE32 0xFFFF #pragma comment(lib, “ws2_32.lib“) /客户端主函数开始 void main() int err = INVALID_VALUE32; WORD ver; WSADATA wsaData; /定义版本号 ver = MAKEWORD(2, 2); /* 版本号为 2.2 版本,1.1 也可以 */ /* 接下来初始化 */ err = WSAStartup(ver, if (err != 0) /* 检查 socket 是否初始化成功 */ return; if (2 != (LOBYTE(wsaData.wVersion) | (2 != HIBYTE(wsaData.wVersion) WSACleanup(); /* 版本错误则清楚导入的 DLL */ return; /* 开始 socket 的主体部分:创建 socket */ SOCKET sockClient = socket(AF_INET, SOCK_DGRAM, 0); /* AF_INET 表示网络使用 的范围 internetwork: UDP, TCP, etc, SOCK_STREAM 表示使 用的是 TCP SOCK_DGRAM 表示使 用的是 UDP 类型 */ SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = inet_addr(“192.168.145.137“); / 这里设置为服务器的 IP 地址,由于我在自己的机器上面写的,所以写回环地址了 addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(7000); /* 端口随便只要不跟系统冲突就行 */ /* 定义几个缓冲区,也是接受和发送的 ,设置成 100 即可 */ char recvbuf100; char sendbuf100; int len=sizeof(SOCKADDR); /* 下面进入死循环 */ while (1) printf(“nEnter a line:n“); gets(sendbuf); sendto(sockClient, sendbuf, strlen(sendbuf)+1, 0, (SOCKADDR *) int recvnum = recvfrom(sockClient, recvbuf, 100, 0, (SOCKADDR *) recvbufrecvnum = 0; /* 将接收到的数据存入数据缓冲区,以便显示 */ printf(“Receive a line %s“, recvbuf); /* 最后将 socket 清空 */ closesocket(sockClient); WSACleanup(); return; 【TCP】 Server 端源码: #include #include #include #include #include #define PORT 7000 main () struct sockaddr_in client, server;/ 客户端地址信息 本机地址信息 int s, ns, namelen, pktlen;/s:监听 socket ns:数据传输 socket namelen:client 的地址长度 pktlen:传送数据的字节数 char buf400; char buf3200; s=socket(AF_INET, SOCK_STREAM, 0); /创建连接的 SOCKET,s 为 socket 描述符 / 初始化服务器地址 memset (char *) /将已开辟内存空间 server 的全部字节的值设为 值 0.类似于 bzero server.sin_family = AF_INET; server.sin_port = htons(PORT);/端口号 server.sin_addr.s_addr = INADDR_ANY;/设置网络地址,INADDR_ANY 表示机器的 IP 地址 /server 需要在 listen 之前绑定一个大家都知道的地址,就是刚刚初始化好的 ip+端口号 bind(s, (struct sockaddr *) listen(s,1);/侦听客户端请求 ,i 为 socket 可以排队链接的最大个数 /*接受 client 请求 ,s 为 server 的描述符( 即监听 socket 描述符),第二个参数即指针 client 的协 议地址,第三个参数代表地址长度 返回值 ns 是一个全新的描述符,是数据传输 socket,代表与返回客户的 tcp 连接*/ namelen = sizeof (client); ns = accept (s, (struct sockaddr *) /开始进行网络 I/O for (;) /*recv 接受 client 发送的数据,recv 函数仅仅是 copy 数据,真正的接收数据是协议来
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 学生旷课检讨书
- 学生乘车交接制度
- 小区配套商业工程监理实施细则
- 物业外包服务人员安全生产责任书
- 教育局家校社协同育人工作汇报范文
- 机关单位文明单位创建制度
- 人教版小学一年级语文下册 两只小狮子 教学设计
- 河北省2026年中考道德与法治真题附答案
- 冷链运输托盘与装载工具管理手册
- 公司规章制度修订完善工作手册
- 2026年邮政营业员(高级工)试题附答案
- 2026浙江省重点初中分班考夺分攻略:数学思维拓展与英语词汇飞跃专项训练
- 2026年浙江(1月)高考英语真题及答案解析
- 2026福建省农业融资担保有限公司招聘3人笔试备考题库及答案详解
- 抽水蓄能电站爆破施工方案
- 2026-2030中国钇行业运行现状与投资前景预测分析报告
- 2026年钛材行业分析报告及未来发展趋势报告
- 2026年重症肺炎的诊断与治疗
- 水利行业从业人员安全培训手册
- 重卡维修站规范制度
- 心电图机操作课件
评论
0/150
提交评论