UDP实现简单通讯(夕佳佳)

1、概念

  1. 网络通信如何识别通讯双方:(五元组) 一个本机IP对应自己的电脑,远程IP对应一个别人的电脑; 以及电脑有多个运行的程序,用端口号区分不同的程序

    并且使用协议名最终确定

  2. INADDR_ANY 泛指本机IP(即0.0.0.0)

    #define INADDR_ANY              (ULONG)0x00000000

  3. 客户端和服务端的地址设置: 地址都是表明自己的,所以服务端必然是本机,客户端就是其他人电脑对应的IP

2、实现流程图

借用丙佬的图,顺便附上链接基于 UDP 的套接字通信 | 爱编程的大丙 (subingwen.cn)

(本质上我自己没有完成互相通讯,只有一个单向传播嘤嘤嘤)

3、代码分段解读(其实算是分功能)

  1. /*初始化WSA*/
    ​
    WSADATA data;          //创建对象
    int error = WSAStartup(MAKEWORD(2, 2), &data);//WSA 是windows socket api,这里创建一个对象?可以回来补充!;MAKEWORD(2,2)是使用version2.2的套接字
    if (error != 0)
    {
        printf("error\n");
        return 1;
    }
    //这里检查版本对不对,高字节是主版本,低字节是副版本
    if (HIBYTE(data.wVersion) != 2 || LOBYTE(data.wVersion) != 2)
    {
        WSACleanup();
        printf("version wrong\n");
        return 0;
    }

  2. /*实例化SOCKET*/
    ​
    SOCKET client_sock = socket(AF_INET, SOCK_DGRAM, 0);
    ​
    //第一个是地址类型;第二个是套接字类型;第三个是要使用的通讯协议
    //其他参数见官方doc
    //https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket

  3. /*实例化SOCKADDR_IN*/
    ​
    SOCKADDR_IN server_address;
    ​
    //三个主要属性:1.sin_addr 表示socket收发地址,这是一个结构体;常见的有
    server_address.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    //或者↓这下面的是wsa2.h的表达方式
    inet_pton(AF_INET, "10.136.122.138", &server_address.sin_addr.S_un.S_addr);
    //            2.sin_family  如果用socket编程,似乎只能用AF_INET
    //            3.sin_port   表示该程序的端口号(自己找一个空闲的端口号),有需要对应htons函数
    //具体举个例子
    ​
    server_address.sin_family = AF_INET;
    server_address.sin_port = htons(6666);


  4. /*绑定套接字和地址*/
    bind(server_sock, (SOCKADDR*)&server_address, sizeof(SOCKADDR));

  5. /*初始化一些用于收发的存储量*/
    int len = sizeof(SOCKADDR);
    char  send_buffer[100] = "abbbbb";

  6. 最后简单介绍一下sendtorecvfrom的用法 (1)函数原型

    int WSAAPI sendto(
      [in] SOCKET         s,
      [in] const char     *buf,
      [in] int            len,
      [in] int            flags,
      [in] const sockaddr *to,
      [in] int            tolen
    );
    ​
    //举个例子
    ​
    sendto(client_sock, send_buffer, strlen(send_buffer) + 1, 0, (SOCKADDR*)&server_address, len);
    //这个是客户端发给服务端的句子;第一项就是使用者端的套接字
    //                         第二项目是发送的字符串
    //                         第三项是这个字符串的长度
    //                         第四项俺也不太会,一般默认0
    //                         第五项是发送给的东西的地址,传参传sockaddr结构体的指针
    //                         第六项是这个sockaddr的大小;int len = sizeof(SOCKADDR);
    int WSAAPI recvfrom(
      [in]                SOCKET   s,
      [out]               char     *buf,
      [in]                int      len,
      [in]                int      flags,
      [out]               sockaddr *from,
      [in, out, optional] int      *fromlen
    );
    ​
    //举个例子
    ​
    recvfrom(server_sock, recieve_buffer, sizeof(recieve_buffer), 0, (SOCKADDR*)&client_address, &len);
    //这个是服务端接受客户端发送来的信息的例子;第一项是使用者的套接字
    //                                   第二项是存信息的数组
    //                                   第三项是这个数组长度
    //                                   第四项同上,默认0吧
    //                                   第五项是数据来源的地址,传的同样是sockaddr的指针
    //                                   第六项同前

4、实现代码

(1)功能提醒:就是简单的客户端发,服务端收;这种最基础的都大同小异,可能得掌握bind、端口等具体含义与作用后拓展会更好(这只小菜狗想试着做个狼人杀系统,但是可能大概率寄)

(2)客户端

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <string.h>
​
#pragma comment(lib, "Ws2_32.lib")
​
int main(void)
{
    WSADATA data;
    int error = WSAStartup(MAKEWORD(2, 2), &data);
    if (error != 0)
    {
        printf("error\n");
        return 1;
    }
    if (HIBYTE(data.wVersion) != 2 || LOBYTE(data.wVersion) != 2)
    {
        WSACleanup();
        printf("version wrong?\n");
        return 0;
    }
​
    SOCKET client_sock = socket(AF_INET, SOCK_DGRAM, 0);
​
    //这里考虑去掉,晚上回来试试
    SOCKADDR_IN client_address;
    inet_pton(AF_INET, "10.136.210.98", &client_address.sin_addr.S_un.S_addr);//这里记得换一下,变成其他电脑的ip
    client_address.sin_family = AF_INET;
    client_address.sin_port = htons(6666);
    //去掉↑
​
    //手动加
    SOCKADDR_IN server_address;
    inet_pton(AF_INET, "我自己电脑(服务端)的ip", &server_address.sin_addr.S_un.S_addr);
    server_address.sin_family = AF_INET;
    server_address.sin_port = htons(6666);
​
​
    int len = sizeof(SOCKADDR);
    char  send_buffer[100] = "abbbbb";
​
    printf("Connection established,send \'#\' to disconnect.\n");
​
    while (1)
    {
        puts("enter sth to send:");
        gets_s(send_buffer);
​
​
        sendto(client_sock, send_buffer, strlen(send_buffer) + 1, 0, (SOCKADDR*)&server_address, len);
​
​
    }
    closesocket(client_sock);
    WSACleanup();
    return 0;
}

(3)服务端

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
​
#pragma comment(lib, "Ws2_32.lib")
​
int main(void)
{
    WSADATA data;
    int error = WSAStartup(MAKEWORD(2, 2), &data);
    if (error != 0)
    {
        printf("error\n");
        return 1;
    }
    if (HIBYTE(data.wVersion) != 2 || LOBYTE(data.wVersion) != 2)
    {
        WSACleanup();
        printf("version wrong?\n");
        return 0;
    }
​
    SOCKET server_sock = socket(AF_INET, SOCK_DGRAM, 0);
​
    SOCKADDR_IN server_address;
    server_address.sin_addr.S_un.S_addr = inet_addr("我自己电脑的ip");
    server_address.sin_family = AF_INET;
    server_address.sin_port = htons(6666);
​
    int flag = bind(server_sock, (SOCKADDR*)&server_address, sizeof(SOCKADDR));
    if (flag == -1)
        puts("eeee");
    SOCKADDR_IN client_address;
    //这里加进去的
    client_address.sin_addr.S_un.S_addr = inet_addr("10.135.7.112");//这里记得换一下,变成其他电脑的ip
    client_address.sin_family = AF_INET;
    client_address.sin_port = htons(6666);
    //这里加入
    int len = sizeof(client_address);
    char recieve_buffer[100], send_buffer[100] = "abbbbbbbbbbbbbbbbbb", tmp_buffer[30];
​
    printf("Connection established,send \'#\' to disconnect.\n");
​
    while (1)
    {
        recvfrom(server_sock, recieve_buffer, sizeof(recieve_buffer), 0, (SOCKADDR*)&client_address, &len);
        puts("recieved\n");
        printf("%s\n", recieve_buffer); 
    }
​
    closesocket(server_sock);
    WSACleanup();
​
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

robinbird_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值