为便于理解数据报套接字模型下的编程过程,用时序图表述如下(请注意,时序图不同 于程序流程图,它只是对完成一次通信过程进行原理性描述的手段。
2、实验内容 (1)、理解数据报套接字编程模型,仔细阅读并调试运行 UDPserve.cpp 程序和 UTPClient.cpp 程序源代码,分析在服务端和客户端分别使用了哪些 Winsock API 函数; (2)、修改 UDPServer 和 UDPClient 程序,设计一个简单的 UDP 通信程序,并达到以下要 求:
a.双方能相互发送数据,并显示接收到的数据。
b.当收到对方的数据为“bye”时,能退出程序。
c.编程验证实验思考题中问题。
d.选做,服务器同多个客户端通信。
三、实验过程(包含实验结果) 1、运行服务器和客户端程序
2、开始通信 服务器和客户端可以互发消息,收到消息的一方字体会变成亮黄色,用于提示,发送消息成功得而一方字体颜色恢复成白色。
3、多个客户端通信
4、客户端输入“bye”,该客户端退出连接。
a.指定新的IP地址和端口号。
b.断开连接。
这也与TCP有所不同,TCP套接字只能调用一次connect()函数。 3、能否在不调用sendto()函数之前调用recvfom()函数? 答:可以。此时只需要在调用recvfrom()函数之前使用bind()绑定地址。 五、总结 本次实验其实很简单,利用UDP协议进行通信,这样的通信并非TCP那样是可靠的传输,实验中用到最主要的值recvfrom()、sendto()两个函数,在一个循环中检测有没有收到信息,如果收到消息就将其打印出来,并将字体显示为亮黄色,字体变色是我的创新,考虑到提示的作用,所以用了亮黄色。
1.UDP服务器
#include "stdafx.h" #include <stdio.h> #include <winsock.h> #include <string.h> #include <iostream> #pragma comment(lib,"wsock32.lib") using namespace std; int main() { WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); // 创建套节字 SOCKET s = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (s == INVALID_SOCKET) { printf("Failed socket() \n"); return 0; } // 填充sockaddr_in结构 sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(4567); sin.sin_addr.S_un.S_addr = INADDR_ANY; // 绑定这个套节字到一个本地地址 if (::bind(s, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR) { printf("Failed bind() \n"); return 0; } // 接收数据 char receivebuff[1024]; char sendbuff[1024]; sockaddr_in addr; int nLen = sizeof(addr); printf("-----------------我是服务器-------------------------:\n"); while (TRUE) { int nRecv = ::recvfrom(s, receivebuff, 1024, 0, (sockaddr*)&addr, &nLen); if (nRecv > 0) { //接收数据 system("color 0E"); receivebuff[nRecv] = '\0'; printf("从客户端接收到信息: %s\n", receivebuff); if (strcmp(receivebuff, "bye") == 0) { ::closesocket(s); return 0; } //发送数据 // scanf("%s", sendbuff); } gets(sendbuff); ::sendto(s, sendbuff, strlen(sendbuff), 0, (sockaddr*)&addr, sizeof(addr)); system("color 0F"); printf("服务器发送信息: %s\n", sendbuff); if (strcmp(sendbuff, "bye") == 0) { ::closesocket(s); return 0; } } return 0; }2、UDP客户端
#include "stdafx.h" #include <stdio.h> #include <winsock.h> #include <iostream> #pragma comment(lib,"wsock32.lib") using namespace std; int main() { WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); // 创建套节字 SOCKET s = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (s == INVALID_SOCKET) { printf("Failed socket() %d \n", ::WSAGetLastError()); return 0; } // 也可以在这里调用bind函数绑定一个本地地址,否则系统将会自动安排 // 填写远程地址信息 sockaddr_in addr; sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(4567); int nLen = sizeof(addr); // 注意,这里要填写服务器程序所在机器的IP地址,如果你的计算机没有联网,直接使用127.0.0.1即可 addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // 发送数据 char receivebuff[1024]; char sendbuffer[1024]; printf("-----------------我是客户端-------------------------:\n"); while (TRUE) { int nRecv = ::recvfrom(s, receivebuff, 1024, 0, (sockaddr*)&addr, &nLen); if (nRecv > 0) { //接收数据 system("color 0E"); receivebuff[nRecv] = '\0'; printf("从服务器接收到信息: %s\n", receivebuff); if (strcmp(receivebuff, "bye") == 0) { ::closesocket(s); return 0; } } //发送数据 // scanf("%s", sendbuffer); gets(sendbuffer); ::sendto(s, sendbuffer, strlen(sendbuffer), 0, (sockaddr*)&addr, sizeof(addr)); system("color 0F"); printf("客户端发送信息: %s\n", sendbuffer); if (strcmp(sendbuffer, "bye") == 0) { ::closesocket(s); return 0; } } return 0; }
注:本博客源代码下载地址:http://download.csdn.net/detail/dmxexcalibur/9904514