C++ 网络编程之正确使用UDP广播及多播


大多数的事倍功半源于自以为是事半功倍的一念之差。查了两天UDP传输代码,终于从一个博客的一行小字发现了问题的所在。之前为了方便直接运用Linux下写好的客户端代码稍作修改之后去跟linux的服务器对接,造成有的机器收的到数据包有的机器却收不到数据包,或是有时收的到数据包有时收不到数据包的状况。可见不同操作系统之间的移植哪怕是同种语言也并不一定是表面看的那么简单,再者生搬硬套的做法往往得不偿失。下面贴出在网上找到的关于正确使用UDP广播的代码,由于多播和广播相差无几,是故以后会把项目的多播代码贴上,以补全题目内容。

相比TCP,UDP的优点是传输速度快且能对整个网络广播数据。但我以前在使用UDP整个网络广播数据的用法上,一直没能好好使用。这段时间,正好需要使用UDP的这个功能,因此经过摸索,得出了一种使用方法如下:(不一定是最好的,但能实现我的功能)

Python实现UDP通信

Unix-domain-socket详解UDP

Linux网络编程之使用UDP传输文件

Java 使用 TCP 和 UDP 传输文件

Java 获取可用 UDP 端口号的方法

Linux程序设计之套接字:UDP

// 服务器端
// Server.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <WinSock2.h>
#include <stdio.h>
#include <iostream>
using namespace std;

#pragma comment(lib, "ws2_32.lib")

const int MAX_BUF_LEN = 255;

int _tmain(int argc, _TCHAR* argv[])
{
 WORD wVersionRequested;
 WSADATA wsaData;
 int err;

 // 启动socket api
 wVersionRequested = MAKEWORD( 2, 2 );
 err = WSAStartup( wVersionRequested, &wsaData );
 if ( err != 0 )
 {
  return -1;
 }

 if ( LOBYTE( wsaData.wVersion ) != 2 ||
  HIBYTE( wsaData.wVersion ) != 2 )
 {
   WSACleanup( );
   return -1;
 }

 // 创建socket
 SOCKET connect_socket;
 connect_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 if(INVALID_SOCKET == connect_socket)
 {
  err = WSAGetLastError();
  printf("/"socket/" error! error code is %d/n", err);
  return -1;
 }

 SOCKADDR_IN sin;
 sin.sin_family = AF_INET;
 sin.sin_port = htons(3779);
 sin.sin_addr.s_addr = INADDR_BROADCAST;

 bool bOpt = true;
 //设置该套接字为广播类型
 setsockopt(connect_socket, SOL_SOCKET, SO_BROADCAST, (char*)&bOpt, sizeof(bOpt));

 int nAddrLen = sizeof(SOCKADDR);

 char buff[MAX_BUF_LEN] = "";
 int nLoop = 0;
 while(1)
 {
  nLoop++;
  sprintf(buff, "%8d", nLoop);

  // 发送数据
  int nSendSize = sendto(connect_socket, buff, strlen(buff), 0, (SOCKADDR*)&sin, nAddrLen);
  if(SOCKET_ERROR == nSendSize)
  {
   err = WSAGetLastError();
   printf("/"sendto/" error!, error code is %d/n", err);
   return -1;
  }
  printf("Send: %s/n", buff);
  Sleep(500);
 }

 return 0;
}

// 客户端
// Client.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <WinSock2.h>
#include <stdio.h>

#pragma comment(lib, "ws2_32.lib")

const int MAX_BUF_LEN = 255;

int _tmain(int argc, _TCHAR* argv[])
{
 WORD wVersionRequested;
 WSADATA wsaData;
 int err;

 // 启动socket api
 wVersionRequested = MAKEWORD( 2, 2 );
 err = WSAStartup( wVersionRequested, &wsaData );
 if ( err != 0 )
 {
  return -1;
 }

 if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 )
 {
   WSACleanup( );
   return -1;
 }

 // 创建socket
 SOCKET connect_socket;
 connect_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 if(INVALID_SOCKET == connect_socket)
 {
  err = WSAGetLastError();
  printf("/"socket/" error! error code is %d/n", err);
  return -1;
 }

 // 用来绑定套接字
 SOCKADDR_IN sin;
 sin.sin_family = AF_INET;
 sin.sin_port = htons(3779);
 sin.sin_addr.s_addr = 0;

 // 用来从网络上的广播地址接收数据
 SOCKADDR_IN sin_from;
 sin_from.sin_family = AF_INET;
 sin_from.sin_port = htons(3779);
 sin_from.sin_addr.s_addr = INADDR_BROADCAST;

 //设置该套接字为广播类型,
 bool bOpt = true;
 setsockopt(connect_socket, SOL_SOCKET, SO_BROADCAST, (char*)&bOpt, sizeof(bOpt));

 // 绑定套接字
 err = bind(connect_socket, (SOCKADDR*)&sin, sizeof(SOCKADDR));
 if(SOCKET_ERROR == err)
 {
  err = WSAGetLastError();
  printf("/"bind/" error! error code is %d/n", err);
  return -1;
 }

 int nAddrLen = sizeof(SOCKADDR);
 char buff[MAX_BUF_LEN] = "";
 int nLoop = 0;
 while(1)
 {
  // 接收数据
  int nSendSize = recvfrom(connect_socket, buff, MAX_BUF_LEN, 0, (SOCKADDR*)&sin_from, &nAddrLen);
  if(SOCKET_ERROR == nSendSize)
  {
   err = WSAGetLastError();
   printf("/"recvfrom/" error! error code is %d/n", err);
   return -1;
  }
  buff[nSendSize] = '/0';
  printf("Recv: %s/n", buff);
 }

 return 0;
}

本文永久更新链接地址:

相关内容