网络编程学习笔记五:Socket UDP 实例编程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011857683/article/details/82564185

1 概述


(1) 基于UDP的服务器端流程

(a) 创建套接字(socket)
(b) 将套接字和IP地址、端口号绑定在一起(bind)
(c) 等待客户端发起数据通信(recvfrom/recvto)
(d) 关闭套接字


(2) 基于UDP的客户端流程

(a) 创建套接字(socket)
(b) 向服务器发起通信(recvfrom/recvto)
(c) 关闭套接字

(3) 基于UDP的socket编程流程图

基于UDP的socket编程不需要设置监听和发起/接收请求,可以直接相互通信,流程如下:
 

2 实例

2.1 UDP unix socket

(1) 客户端

############ udp_unix_socket_client.cpp   ##############

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <errno.h>
#include <stdarg.h>
#include <unistd.h>
#include <pthread.h>
#include <malloc.h>


//unix socket文件路径
#define SERVER_UNIX_SOCKET_FILE  "/tmp/server_unix_socket"
//unix socket文件路径长度
#define UNIX_SOCK_FILE_LEN       (64)
//客户端socket发送缓冲区设置
#define SOCKET_BUFF              (1024)
//socket接收发送超时
#define SOCKET_TIMEOUT_SEC       (5)


/*
    * 功能:  通过随机数生成一个文件路径
    * 参数1: 生成文件存到数组
    * 参数2: 数组大小
    * 返回值, >=0表示成功, <0表示失败
*/
int getClientSocketFile(char *file_path, const int size)
{
    if(NULL == file_path || size <= 0)
    {
        printf("getClientSocket_file file path is null or size(%d) is error!\n", size);
        return -1;
    }


    memset(file_path, 0, size);
    snprintf(file_path, size - 1, "/tmp/client_unix_socket_%u", (unsigned int)pthread_self());
 
 
    return 0;
}


/*
    * 功能:  客户端发送数据给服务端接口
    * 参数1:服务端监听的文件路径
    * 参数2:要发送的数据
    * 参数3:要发送的数据长度
    * 参数4: 接收的数据存放到数组
    * 参数5: 接收数组大小
    * 返回值:>=0表示成功, <0表示失败
*/
int socketSendData(const char* server_file,
                   const char* send_data,
                   const int send_data_size,
                   char* recv_data,
                   const int recv_data_size)
{
    //参数空值检测
    if(NULL == server_file || NULL == send_data || NULL == recv_data)
    {
        printf("socketSendData server_file or send_data or recv_data is null!\n");
        return -1;
    }


    //参数大小检测
    if(0 >= send_data_size || SOCKET_BUFF <= send_data_size ||
       0 >= recv_data_size)
    {
        printf("socketSendData send_data_size(%d) or recv_data_size(%d) error!\n", send_data_size, recv_data_size);
        return -1;
    }


    //创建客户端socket
    int client_sock = socket(AF_UNIX, SOCK_DGRAM, 0);
    if(0 > client_sock)
    {
        printf("socketSendData create socket err(%d)!\n", errno);
        return -1;
    }


    //设置超时时间
    struct timeval times;
    times.tv_sec = SOCKET_TIMEOUT_SEC;
    times.tv_usec = 0;
    int times_size = sizeof(times);


    //接收超时设置
    if(setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, &times, times_size))
    {
        printf("socketSendData setsockopt rcv time err(%d)!\n", errno);
        close(client_sock);
        return -1;
    }


    //发送超时设置
    if(setsockopt(client_sock, SOL_SOCKET, SO_SNDTIMEO, &times, times_size))
    {
        printf("socketSendData setsockopt send time err(%d)!\n", errno);
        close(client_sock);
        return -1;
    }


    //设置发送缓冲区
    int buflen = SOCKET_BUFF;
    if(setsockopt(client_sock, SOL_SOCKET, SO_SNDBUF, &buflen, sizeof(buflen)))
    {
        printf("socketSendData setsockopt send buflen err(%d)!\n", errno);
        close(client_sock);
        return -1;
    }


    //设置接收缓冲区
    if(setsockopt(client_sock, SOL_SOCKET, SO_RCVBUF, &buflen, sizeof(buflen)))
    {
        printf("socketSendData setsockopt recv buflen err(%d)!\n", errno);
        close(client_sock);
        return -1;
    }


    //获取一个随机文件路径
    char client_file[UNIX_SOCK_FILE_LEN] = {0};
    getClientSocketFile(client_file, sizeof(client_file));
    printf("socketSendData client socket file(%s)!\n", client_file);


    //绑定客户端socket文件
    struct sockaddr_un addr_cli;
    memset(&addr_cli, 0, sizeof(addr_cli));
    addr_cli.sun_family = AF_UNIX;
    strncpy(addr_cli.sun_path, client_file, sizeof(addr_cli.sun_path) - 1);
    unlink(client_file);
    if(bind(client_sock, (struct sockaddr*)&addr_cli, sizeof(addr_cli)) < 0)
    {
        printf("socketSendData tcp bind err(%d)!\n", errno);
        close(client_sock);
        return -1;
    }


    //构造服务端地址
    struct sockaddr_un  addr_svr;
    memset(&addr_svr, 0, sizeof(addr_svr));
    addr_svr.sun_family = AF_UNIX;
    strncpy(addr_svr.sun_path, server_file, sizeof(addr_svr.sun_path) - 1);
    if(connect(client_sock, (struct sockaddr*)&addr_svr, sizeof(addr_svr)) < 0)
    {
        printf("socketSendData tcp connect err(%d)!\n", errno);
        close(client_sock);
        unlink(client_file);
        return -1;
    }


    //发送数据包
    int len = send(client_sock, send_data, send_data_size, 0);
    if(len != send_data_size)
    {
        printf("socketSendData unix socket send err(%d)!\n", errno);
        close(client_sock);
        unlink(client_file);
        return -1;
    }


    //接收返回数据
    len = recv(client_sock, recv_data, recv_data_size - 1, 0);
    if(len <= 0)
    {
        printf("socketSendData unix socket recv err(%d)!\n", errno);
        close(client_sock);
        unlink(client_file);
        return -1;
    }


    printf("socketSendData recv data(%s)!\n", recv_data);


    close(client_sock);
    unlink(client_file);
    return 0;
}


int main()
{
    char send_data[SOCKET_BUFF] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
    char recv_data[SOCKET_BUFF] = {0};

    socketSendData(SERVER_UNIX_SOCKET_FILE,
                   send_data,
                   strlen(send_data),
                   recv_data,
                   SOCKET_BUFF);
                   
    printf("%s\n", recv_data);

    return 0;  
}

(2) 服务端

############ udp_unix_socket_client.cpp   ##############

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <errno.h>
#include <stdarg.h>
#include <unistd.h>
#include <pthread.h>
#include <malloc.h>
#include <signal.h>
 
 
//unix socket文件路径
#define SERVER_UNIX_SOCKET_FILE  "/tmp/server_unix_socket"
//unix socket文件路径长度
#define UNIX_SOCK_FILE_LEN       (64)
//客户端socket发送缓冲区设置
#define SOCKET_BUFF              (1024)
//最大客户端连接数
#define BACKLOG                  (5)
 
 
 
//设备信息
#define JSON_DATA_1               "{" \
                                  "\"method\": \"HOST_GET_Ret_Eui64\"," \
                                  "\"longAddress\":[" \
                                  "{\"eui64\": \"AAA\", \"type\": 1, \"deviceEndpoint\":1}," \
                                  "{\"eui64\": \"BBB\", \"type\": 2, \"deviceEndpoint\":2}]" \
                                  "}"
 
 
/*
    * 功能:  socket服务器
*/
void udpServer()
{
    int i                 = 0;
    int j                 = 0;
    int ret               = 0;
    int udpSocket         = -1;
    struct sockaddr_un sun;
    struct sockaddr_un remoteAddr;
    char  u8RecvBuf[SOCKET_BUFF]  = {0};
 
    unsigned int u32RemoteAddrLen = sizeof(remoteAddr);
 
    printf("udpServer start\n");
 
    //创建套接字
    udpSocket = socket(AF_UNIX, SOCK_DGRAM, 0);
    if(udpSocket < 0)
    {
        printf("tcpServer socket error!\n");
        exit(1);
    }
 
    //绑定
    memset(&sun, 0, sizeof(sun));
    sun.sun_family = AF_UNIX;
    strncpy(sun.sun_path, SERVER_UNIX_SOCKET_FILE, sizeof(sun.sun_path)-1);  
    unlink(SERVER_UNIX_SOCKET_FILE);  
 
    if((bind(udpSocket, (struct sockaddr *)&sun, sizeof(sun))) < 0)
    {
        printf("udpServer bind error(%d)!\n", errno);
        close(udpSocket);
        exit(1);
    }
 
    //忽略SIGPIPE信号,防止客户端关闭导致服务端退出
    //signal(SIGPIPE, SIG_IGN);
 
    //循环接收数据
    while (1)
    {
        ret = recvfrom(udpSocket, u8RecvBuf, sizeof(u8RecvBuf), 0, (struct sockaddr *)&sun, &u32RemoteAddrLen);
        if(ret < 0)
        {
            if(errno == EAGAIN || errno == EINTR)
            {
                //超时或者信号中断属于正常情况
                printf("udpServer recv timeout or intrrupt signal continue recv!\n");
                continue;
            }
 
            //socket接收出错
            printf("udpServer socket recv err(%d)\n", errno);
            continue;
        }
        else if (ret == 0)
        {
            //对方关闭socket
            printf("udpServer ret(%d) and client(%d) close!\n", ret, udpSocket);
        }
        else
        {
            if (ret < SOCKET_BUFF)
            {
                memset(&u8RecvBuf[ret], '\0', 1);
            }
            printf("udpServer client(%d) recv(%s)!\n",udpSocket, u8RecvBuf);
            
            //发送数据到客户端,这里开始处理接收的数据
            sendto(udpSocket, JSON_DATA_1, strlen(JSON_DATA_1) + 1, 0, (struct sockaddr *)&sun, u32RemoteAddrLen);
        }
    }
 
    //关闭服务端
    close(udpSocket);
    unlink(SERVER_UNIX_SOCKET_FILE);  
    return;
}


int main()
{
   udpServer();
   
   return 0;
}
 

猜你喜欢

转载自blog.csdn.net/u011857683/article/details/82564185