在我的上两篇博文中已详尽解析TCP的Client/Server传输。本篇博文记录Windows的Cient端和Linux服务端的UDP传输。
#define _CRT_SECURE_NO_WARNINGS
#include
#pragma comment(lib, "WS2_32")
#include
#include
#include
#define BUF_SIZE 1024
using namespace std;
int udp_client(){
WSADATA wsadata;
int iRet = 0;
// 初始化套接字动态库
if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0){
iRet = WSAGetLastError();
printf("WSAStartup failed !\n");
return -1;
}
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wVersion) != 2)
{
printf("Wrong version!\n");
WSACleanup();
return 0;
}
SOCKADDR_IN servAddr;
SOCKET sockClient = socket(AF_INET,
SOCK_DGRAM,
IPPROTO_IP
);
if (sockClient == INVALID_SOCKET) {
cout << "Socket 创建失败,Exit!";
return 0;
}
// 设置服务器地址
servAddr.sin_family = AF_INET;
servAddr.sin_addr.S_un.S_addr = inet_addr("39.105.16.186");
servAddr.sin_port = htons(6555);
char strSend[BUF_SIZE];
char strRecv[BUF_SIZE];
sprintf(strSend, "Hello World! This is client");
memset(strRecv,0,sizeof(strRecv));
int nServAddLen = sizeof(servAddr);
// 向服务器发送数据
iRet = sendto(sockClient, strSend, BUF_SIZE, 0, (sockaddr *)&servAddr, nServAddLen);
if (iRet == SOCKET_ERROR){
printf("sendto() failed:%d\n", WSAGetLastError());
closesocket(sockClient);
WSACleanup();
return -1;
}
printf("msg has been sent!\n");
// 从服务器接收数据
iRet = recvfrom(sockClient, strRecv, BUF_SIZE, 0, (sockaddr *)&servAddr, &nServAddLen);
if (iRet == SOCKET_ERROR)
{
printf("recvfrom failed:%d\n", WSAGetLastError());
closesocket(sockClient);
WSACleanup();
return -1;
}
printf("Recv From Server:%s\n", strRecv);
if (!closesocket(sockClient))
{
WSAGetLastError();
return 0;
}
if (!WSACleanup())
{
WSAGetLastError();
return 0;
}
cout << "客户端关闭" << endl;
return 0;
}
int main(){
//tcp_client();
udp_client();
}
#include
#include
#include
#include
#include
#include
#include
#define SERVER_PORT 6555
#define BUFF_LEN 1024
void handle_udp_msg(int fd)
{
char buf[BUFF_LEN];
socklen_t len;
int iRet;
struct sockaddr_in clent_addr;
while(1)
{
memset(buf, 0, BUFF_LEN);
len = sizeof(clent_addr);
iRet = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr*)&clent_addr, &len);
if(iRet == -1)
{
printf("recieve data fail!\n");
return;
}
printf("Msg received! client:%s\n",buf);
memset(buf, 0, BUFF_LEN);
sprintf(buf, "I have recieved %d bytes data!\n", iRet);
printf("Answer has been sent:%s\n",buf);
sendto(fd, buf, sizeof(buf), 0, (struct sockaddr*)&clent_addr, len);
}
}
/*
server:
socket-->bind-->recvfrom-->sendto-->close
*/
int main(int argc, char* argv[])
{
int server_fd, ret;
struct sockaddr_in ser_addr;
server_fd = socket(AF_INET, SOCK_DGRAM, 0); //AF_INET:IPV4;SOCK_DGRAM:UDP
if(server_fd < 0)
{
printf("create socket fail!\n");
printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
return -1;
}
memset(&ser_addr, 0, sizeof(ser_addr));
ser_addr.sin_family = AF_INET;
ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
ser_addr.sin_port = htons(SERVER_PORT);
ret = bind(server_fd, (struct sockaddr*)&ser_addr, sizeof(ser_addr));
if(ret < 0)
{
printf("socket bind fail!\n");
printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
return -1;
}
printf("======waiting for client's request======\n");
handle_udp_msg(server_fd);
close(server_fd);
return 0;
}
https://linux.die.net/man/2/recv
再上个可以看文档的地址。
细枝末节在前两篇博文已全部分析详尽。UDP相比于TCP最大的区别有二:
一是不需要连接,所以加快了传输速度,但是也加大了丢包的可能,
二是使用sendto/recvfrom。这是因为在没有连接的状态下,如果不指定地址,无法发送数据。recvfrom和recv是差不多的,相比于recv,recvfrom可以接收发送地址等额外数据。在服务器端,如果没有用recvfrom得到源服务器地址,就无法发出反馈信息。