windows系统下UDP通信的具体实现

  1. Winsock 编程模型
    Winsock 编程的主要模型分为流套接字编程模型和数据报套接字编程模型两类,主要区
    别在于:前者提供双向的、有序的、无重复并且无记录边界的数据流服务,即采用有连接的
    数据传输服务,保证数据可靠到达;后者也支持双向数据流,但不能保证数据的可靠、有序
    和无重复,它保留了记录边界,是一种无连接、不可靠的数据传输模型。
  2. 数据报套接字编程模型
    数据报套接字使用UDP 协议进行数据的传输,是一种无连接的数据传输模型,编程过程
    相对简单,采用客户/服务器(C/S)结构进行设计。
    在数据报套接字编程模型中,客户端发送数据(也称发送端),服务器端接收数据(也
    称接收端)。实际上,由于数据报套接字编程模型也支持双向数据传递,因此,服务器端和
    客户端的概念已经比较模糊。为了说明数据报套接字编程模型的工作原理,这里仍然沿用这
    两个概念。
    数据报套接字的服务进程和客户进程不需要在通信前建立连接,仅需要创建各自的套接
    字,因此程序设计过程相当简单,简述如下:
    接收端:1、创建数据报套接字;2、绑定本机地址和端口;3、等候接收数据;4、使用
    完成后关闭套接字。
    发送端:1、创建数据报套接字;2、向指定地址和端口发送数据;3、使用完成后关闭
    套接字。
  3. 数据报套接字编程使用的函数
  1. 创建套接字函数socket()
    SOCKET socket(int af,int type,int protocol);
    由于采用数据报套接字进行数据传输,因此type 参数必须设置为SOCK_DGRAM,
    protocol 参数必须设置为IPPROTO_UDP
  2. 绑定本地地址到所创建的套接字函数bind()
    int bind(SOCKET s,const struct sockaddr* name,int namelen);
    在实际编程时可以省略该函数,系统会自动绑定
  3. 接收数据函数recvfrom()
    int recvfrom(SOCKET s,char* buf,int len,int flags,
    struct sockaddr* from,int* fromlen);
  4. 发送数据函数sendto()
    int sendto(SOCKET s,const char* buf,int len,int flags,
    const struct sockaddr* to,int* tolen);
  5. 关闭套接字函数closesocket()
    int closesocket(SOCKET s);
  1. 数据报套接字编程模型时序和流程
    为便于理解数据报套接字模型下的编程过程,用时序图表述如下(请注意,时序图不同于程序流程图,它只是对完成一次通信过程进行原理性描述的手段。
    4 实验内容
    1、认真理解数据报套接字编程模型,仔细阅读并调试运行UDPserve.cpp 程序和
    UTPClient.cpp 程序源代码,分析在服务端和客户端分别使用了哪些Winsock API 函数,写
    入实验报告;
    2、修改UDPServer 和UDPClient 程序,设计一个简单的UDP 通信程序,并达到以下要
    求:
    ○1 双方能相互发送数据,并显示接收到的数据。
    ○2 当收到对方的数据为“bye”时,能退出程序。
    代码如下:
    1.服务器端代码:

#include<winsock2.h>
#include<stdio.h>
#include<string.h>
#include
using namespace std;
#pragma comment(lib,“ws2_32.lib”)
#define BUFFER_SIZE 1024
int main(){
WSADATA WSAData;
char receBuf[BUFFER_SIZE];
char Response[]="";
if(WSAStartup(MAKEWORD(2,2),&WSAData)!=0){
printf(“初始化失败”);
exit(1);
}
SOCKET sockServer=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(sockServer == INVALID_SOCKET)
{
printf(“Failed socket() \n”);
return 0;
}
SOCKADDR_IN addr_Server; //服务器的地址等信息
addr_Server.sin_family=AF_INET;
addr_Server.sin_port=htons(4567);
addr_Server.sin_addr.S_un.S_addr=INADDR_ANY;
if(bind(sockServer,(SOCKADDR*)&addr_Server,sizeof(addr_Server))==SOCKET_ERROR ){//服务器与本地地址绑定
printf(“Failed socket() %d \n”, WSAGetLastError());
return 0;
}
SOCKADDR_IN addr_Clt;

int fromlen = sizeof(SOCKADDR);  
while(true){  
    int last=  recvfrom(sockServer, receBuf, 1024, 0,  (SOCKADDR*) &addr_Clt, &fromlen);  
    if(last>0){      //判断接收到的数据是否为空
       receBuf[last]='\0';//给字符数组加一个'\0',表示结束了。不然输出有乱码
       if(strcmp(receBuf,"bye")==0){
              cout<<"                             客户端不跟我聊天了..."<<endl;      
              closesocket(sockServer);  
              return 0;
       }else{
          printf("接收到数据(%s):%s\n", inet_ntoa(addr_Clt.sin_addr), receBuf);
       }
   }
      cout<<"回复客户端消息:";
      cin>>Response; //给客户端回复消息
      sendto(sockServer,Response, strlen(Response), 0, (SOCKADDR*)&addr_Clt, sizeof(SOCKADDR));  
}  

closesocket(sockServer);  

WSACleanup();
 return 0;

}
2.客户端代码:

#include<winsock2.h>
#include<stdio.h>
#include<string.h>
#include
using namespace std;
#pragma comment(lib,“ws2_32.lib”)

define BUFFER_SIZE 1024 //缓冲区大小

int main(){
SOCKET sock_Client; //客户端用于通信的Socket
WSADATA WSAData;
char receBuf[BUFFER_SIZE]; //发送数据的缓冲区
char sendBuf[BUFFER_SIZE]; //接受数据的缓冲区

if(WSAStartup(MAKEWORD(2,2),&WSAData)!=0){
printf("初始化失败!");
return -1;
}    //初始化
sock_Client=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);//创建客户端用于通信的Socket
SOCKADDR_IN addr_server;   //服务器的地址数据结构
addr_server.sin_family=AF_INET;
addr_server.sin_port=htons(4567);//端口号为4567
addr_server.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");   //127.0.0.1为本电脑IP地址
SOCKADDR_IN sock;
int len=sizeof(sock);
while(true){
    cout<<"请输入要传送的数据:";
    cin>>sendBuf;  
    sendto(sock_Client,sendBuf,strlen(sendBuf),0,(SOCKADDR*)&addr_server,sizeof(SOCKADDR));
    //int last=recv(sock_Client, receBuf, strlen(receBuf), 0);              // (调用recv和recvfrom都可以)
    int last=recvfrom(sock_Client,receBuf,strlen(receBuf),0,(SOCKADDR*)&sock,&len);
        if(last>0){
         receBuf[last]='\0';      //给字符数组加一个'\0',表示结束了。不然输出有乱码
            if(strcmp(receBuf,"bye")==0){
                   cout<<"                               服务器不跟我聊天了..."<<endl;//当服务器发来bye时,关闭socket
                   closesocket(sock_Client);
                    break;
            }else{
          printf("接收到数据:%s\n", receBuf);
            }

   }

}
closesocket(sock_Client);
WSACleanup();

return 0;
}

/*
sockaddr和sockaddr_in的区别:
sockaddr常用于bind、connect、recvfrom、sendto等函数的参数,指明地址信息。是一种通用的套接字地址。
而sockaddr_in 是internet环境下套接字的地址形式。
所以在网络编程中我们会对sockaddr_in结构体进行操作。
使用sockaddr_in来建立所需的信息,最后使用类型转化就可以了。
*/

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Windows 操作系统中,UDP 组播是一种同时向多个接收方传递数据包的通信方式。使用 UDP 协议进行组播通信可以减少网络流量,提高通信效率和可靠性。 在 C 语言中实现 UDP 组播,需要使用 Winsock API 进行网络编程。通过调用相关的库函数,实现 UDP 的创建、绑定、发送和接收等操作。 创建 UDP Socket:使用 socket() 函数创建 UDP Socket,确定 IP 地址族(IPv4/IPv6)、协议类型(UDP)和 Socket 类型(组播 Socket)。 绑定 Socket:使用 bind() 函数将 Socket 与指定的 IP 地址和端口号绑定。 发送数据包:使用 sendto() 函数向指定的组播地址和端口号发送数据包。 接收数据包:使用 recvfrom() 函数从组播组中接收数据包,并处理接收到的数据。 在使用 UDP 组播时,需要注意以下几点: 1. 组播地址需要在特定的范围内,一般为224.0.0.0至239.255.255.255的范围内,防止与其他网络通信冲突。 2. 不同的操作系统网络环境下,组播协议的实现可能会有差异,需要根据具体情况进行调试和优化。 3. 组播通信有时会出现丢包或者乱序的情况,需要通过网络协议栈的相关机制进行处理,提高通信可靠性。 总之,UDP 组播是一种高效、可靠、灵活的网络通信方式,适用于多种应用场景,如视频直播、数据传输、分布式计算等。在 C 语言中实现 UDP 组播,需要掌握网络编程基础知识和相关的库函数,结合实际应用需求进行调试和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值