winsock实现UDP通信DEMO

Client

#define _WINSOCK_DEPRECATED_NO_WARNINGS

#include <iostream>
#include <string>
#include <vector>
#include <list>

#include <winsock2.h>

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

namespace udp_client {

class UdpClient {
public:
  bool InitWinsock() {
    WSADATA wsa_data;
    if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) {
      std::cout << "Failed to link winsock.dll!" << std::endl;
      return false;
    }

    return true;
  }

  void ReleaseWinsock() {
    WSACleanup();
  }

  void set_port(u_short port) {
    port_ = port;
  }

  void set_ip(const std::string& ip) {
    ip_ = ip;
  }

  bool Start() {
    SOCKET client_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (client_socket == SOCKET_ERROR) {
      std::cout << "Failed to create socket!" << std::endl;
      return false;
    }

    sockaddr_in client_addr;
    memset(&client_addr, 0, sizeof(sockaddr_in));
    client_addr.sin_family = AF_INET;
    client_addr.sin_port = htons(port_);
    client_addr.sin_addr.S_un.S_addr = inet_addr(ip_.c_str());

    const char* kGreeting = "Hello I'm client!";
    int ret = sendto(client_socket, kGreeting, strlen(kGreeting), 0, (sockaddr*)&client_addr, sizeof(sockaddr));
    if (ret == 0) {
      std::cout << "Failed to send!" << std::endl;
      return false;
    }

    const int kBufSize = 1048;
    char buf[kBufSize] = {};

    sockaddr_in server_addr = { 0 };
    int server_addr_len = sizeof(sockaddr_in);

    ret = recvfrom(client_socket, buf, kBufSize, 0, (sockaddr*)&server_addr, &server_addr_len);
    std::cout << "Receive msg: " << buf << ". IP: " << inet_ntoa(server_addr.sin_addr)
      << " Port: " << ntohs(server_addr.sin_port) << std::endl;

    closesocket(client_socket);
    return true;
  }

private:
  u_short port_;
  std::string ip_;
};

}  // udp_client

#define PORT 6000
#define IP "127.0.0.1"

int main() {
  using namespace udp_client;
  UdpClient client;
  if (!client.InitWinsock()) {
    return 1;
  }

  client.set_port(PORT);
  client.set_ip(IP);

  client.Start();

  client.ReleaseWinsock();

  return 0;
}



Server

#define _WINSOCK_DEPRECATED_NO_WARNINGS

#include <iostream>
#include <string>
#include <vector>
#include <list>

#include <winsock2.h>

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

// 1.TCP是面向连接的,它在通信之前需要进行三次握手来确定双方是否已经准备好了。
// 因此,双方很清楚数据是从哪里来的。
// 而UDP是面向数据包的,因此就好像寄快递一样,你必须在快递上写一张纸条,上面填好姓名,
// 地址等信息,填好之后,接收者才知道该东西是由谁寄过来的。
// 而UDP的收发函数recvform和sendto了sockaddr结构的地址,用于保存从哪里发来的和发送到哪里的地址信息。

// 2.UDP套接口是无连接的、不可靠的数据报协议;既然他不可靠为什么还要用呢?
// 其一:当应用程序使用广播或多播时只能使用UDP协议;其二:由于他是无连接的,所以速度快。
// 因为UDP套接口是无连接的,如果一方的数据报丢失,那另一方将无限等待,解决办法是设置一个超时。
// 建立UDP套接口时socket函数的第二个参数应该是SOCK_DGRAM,说明是建立一个UDP套接口;
// 由于UDP是无连接的,所以服务器端并不需要listen或accept函数。

namespace udp_server {

class UdpServer {
public:
  bool InitWinsock() {
    WSADATA wsa_data;
    if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) {
      std::cout << "Failed to link winsock.dll!" << std::endl;
      return false;
    }

    return true;
  }

  void ReleaseWinsock() {
    WSACleanup();
  }

  void set_port(u_short port) {
    port_ = port;
  }

  bool Start() {
    SOCKET server_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (server_socket == SOCKET_ERROR) {
      std::cout << "Failed to create socket!" << std::endl;
      return false;
    }

    sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port_);
    server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

    bind(server_socket, (sockaddr*)&server_addr, sizeof(server_addr));

    const int kBufSize = 1048;
    char buf[kBufSize] = {};

    while (true) {
      memset(buf, 0, kBufSize);

      // 用来保存客户端的网络信息。
      sockaddr_in client_addr;
      memset(&client_addr, 0, sizeof(sockaddr_in));

      int client_addr_len = sizeof(sockaddr);
      // 接收客户端发来的信息,server阻塞在这里,等待client发来报文。
      int ret = recvfrom(server_socket, buf, kBufSize, 0, (sockaddr*)&client_addr, &client_addr_len);
      std::cout << "Receive msg: " << buf << " from IP:[" << inet_ntoa(client_addr.sin_addr)
                << "], Port:[" << ntohs(client_addr.sin_port) << "]" << std::endl;

      // 发送数据给客户端。
      const char* kGreeting = "Hello, I'm server!";
      sendto(server_socket, kGreeting, strlen(kGreeting), 0, (sockaddr*)&client_addr, client_addr_len);
    }

    closesocket(server_socket);
    return true;
  }

private:
  u_short port_;
};

}  // udp_server

#define PORT 6000

int main2() {
  using namespace udp_server;
  UdpServer server;
  if (!server.InitWinsock()) {
    return 1;
  }

  server.set_port(PORT);

  server.Start();

  server.ReleaseWinsock();

  return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值