基于UDP的socket编程

这几天看protobuf udp都快有点不耐烦了。udp其实感觉写起来比TCP的东西还简单一些,先是写了个控制台的,写了之后想做个界面的,看起来牛逼一点。动手写后,发现mfc里面字符转换啥的,很麻烦,网上找的东西在vs2017里面都用不了。又不想用vc那套老东西了,所以又得找新的资料。反正找的超级烦,本来东西也不是很复杂,但是还是花了不少时间。今天晚上有时间就把东西给记下来了,过几天再实践一下protobuf。

UDP基本操作函数

其实函数和TCP的都差不多。

1. socket()函数

SOCKET socket(int af, int type, int protocol)
  • af IPv4就写AF_INET
  • type 写SOCK_DGRAM
  • protocol 填0就可以了。因为通过前面两个参数一般就可以确定后面的这个是什么类型,前面填了AF_INET,SOCK_DGRAM 适用的就是UDP了。

2. bind()函数
这里服务器调用就可以了,将本机IP地址,选定的一个端口与前面的套接字绑定。客户端的话,就可以不用了。

int bind(SOCKET sock, const struct sockaddr *addr, int addrlen);  
  • 如果bind()返回成功,就会返回0。
  • 如果返回不成功,可以调用GetLastError() 函数,通过错误编码查看是什么错误。

3. 数据的接收和发送
哈哈,这里不像TCP那里那么麻烦,还有一堆函数。服务器绑定地址后,就可以直接发送接受消息了。当然客户端创建成功套接字后也就可以直接接受和发送了。
我用的是sendto(),recvfrom()。

1). sendto()

int sendto(
  _In_       SOCKET                s,//前面创建的套接字
  _In_ const char                  *buf,//要发送的消息
  _In_       int                   len,//消息长度
  _In_       int                   flags,
  _In_       const struct sockaddr *to,//要发的目的地址
  _In_       int                   tolen//to的长度值
);
  • to 就是要送的目的端的地址,所以发送之前得赋值号目的端的IP,端口号等。

2). recvfrom()

int recvfrom(
  _In_        SOCKET          s,//前面创建的套接字
  _Out_       char            *buf,//接受消息的数据缓冲区
  _In_        int             len,//缓冲区长度
  _In_        int             flags,//作用我也没试过,填0就是 哈哈
  _Out_       struct sockaddr *from,//指向装有源地址的缓冲区 传个未赋值的地址指针就行,会返回出发送方的地址
  _Inout_opt_ int             *fromlen//指向from缓冲区长度值。 
返回
);
  • from fromlen两个都是指针类型
  • recvform()有阻塞作用,就是运行到这一句程序会暂停,直到有消息发送过来。

4. 关闭连接
调用closesocket()。

源码

  • 服务器端
#include <iostream>
#include  <winsock2.h>
#include <ws2tcpip.h>
using namespace std;

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

int main()
{
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);//这里因为是Windows下所以要先加载这个

    SOCKET sersock = socket(AF_INET, SOCK_DGRAM, 0);

    sockaddr_in sockAddr;//创建一个sockaddr_in 结构体,分配一个端口号
    memset(&sockAddr, 0, sizeof(sockaddr));
    sockAddr.sin_family = AF_INET;
    sockAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//填本机的IP也可以
    sockAddr.sin_port = htons(8888);

    int test;
    test = bind(sersock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));//将套接字与地址绑定
    if(test != 0)//如果出错可以了通过这个找的错误编码
    {
        DWORD err;
        err = GetLastError();
        cout << "error : " << err << endl;
        return -1;
    }
    char buf[100] = { 0 };
    sockaddr_in clnAddr;
    int len = sizeof(clnAddr);
    memset(&clnAddr,0,len);//清空这个结构体
    recvfrom(sersock, buf, 100, 0, (SOCKADDR*)&clnAddr, &len);//等待客户端发送数据
    //如果recvfrom()返回成功,clnAddr会的填入对方的IP地址和端口,所以后面用这个地址又可以继续向对方发送消息了
    cout << buf << endl;
    cout << ntohs(clnAddr.sin_port) << endl;
    strcpy(buf, "hhh");
    sendto(sersock, buf, 100, 0, (SOCKADDR*)&clnAddr, len);//向前面的clnAddr方发送消息 就是发送的时候的得知道对方的地址、端口号
    closesocket(sersock);
    WSACleanup();
    system("pause");
}
  • 客户端
#include <iostream>
#include <string>
#include  <winsock2.h>
#include <ws2tcpip.h>
using namespace std;

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

int main()
{
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);

    SOCKET clnsock = socket(PF_INET, SOCK_DGRAM, 0);

    sockaddr_in sockAddr;//这里存储的是服务器的地址、端口号
    memset(&sockAddr, 0, sizeof(sockaddr));
    sockAddr.sin_family = AF_INET;
    sockAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    sockAddr.sin_port = htons(8888);


    char buf[100] = { 0 };
    cin >> buf;
    int len = sizeof(sockAddr);
    sendto(clnsock, buf, strlen(buf), 0, (SOCKADDR*)&sockAddr, len);//向服务器发送消息
    memset(&sockAddr, 0, sizeof(sockAddr));//然后将这个结构体清空,再用在下面的recvfrom()函数里面,会发现里面又填充了发送方的地址
    recvfrom(clnsock, buf, 100, 0, (SOCKADDR*)&sockAddr, &len);
    cout << buf << endl;
    closesocket(clnsock);
    WSACleanup();
    system("pause");
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值