Windows/Linux下Socket网络通信UDP传输Client/Server端的C/C++实现详解

前言

在我的上两篇博文中已详尽解析TCP的Client/Server传输。本篇博文记录Windows的Cient端和Linux服务端的UDP传输。

代码

Client端

#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();
}

Server端

#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

再上个可以看文档的地址。

sendto/recvfrom

细枝末节在前两篇博文已全部分析详尽。UDP相比于TCP最大的区别有二:
一是不需要连接,所以加快了传输速度,但是也加大了丢包的可能,
二是使用sendto/recvfrom。这是因为在没有连接的状态下,如果不指定地址,无法发送数据。recvfrom和recv是差不多的,相比于recv,recvfrom可以接收发送地址等额外数据。在服务器端,如果没有用recvfrom得到源服务器地址,就无法发出反馈信息。

你可能感兴趣的:(Networking)