基于UDP的socket编程

xiaoxiao2021-02-28  59

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

UDP基本操作函数

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

1. socket()函数

SOCKET socket(int af, int type, int protocol) af IPv4就写AF_INETtype 写SOCK_DGRAMprotocol 填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"); }
转载请注明原文地址: https://www.6miu.com/read-85240.html

最新回复(0)