UDP - C/S model

        Since UDP does not need to maintain connections, the program logic is much simpler, but the UDP protocol is unreliable, and the mechanism to ensure communication reliability needs to be implemented at the application layer.

communication function

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);

parameter:

        sockfd: socket

        buf: buffer address

        len: buffer size

        flags: 0

        src_addr: (struct sockaddr *)&addr outgoing. Peer address structure

        addrlen: incoming and outgoing.

return value:

        Success: Number of data bytes received.

        Failure: -1 errn.

        0: The peer is closed. 

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

parameter: 

        sockfd: socket

        buf: buffer to store data

        len: data length

        flags: 0

        src_addr: (struct sockaddr *)&addr passed in. target address structure

        addrlen: address structure length.

return value:

        Success: The number of data bytes is written.

        Failure: -1, errno    

UDP communication implementation process

/* 编程模型 */
Server							Client
创建套接字(socket)				创建套接字(socket)
准备地址(本机地址sockaddr_in)	准备地址(目标机地址sockaddr_in)
绑定(bind(sockfd+addr))			.....
接受请求(recvfrom)				发送请求(sendto)
响应请求(sendto)					接受请求(recvfrom)
关闭套接字(close)				关闭套接字(close)

Server side code implementation

  • Step description of UDP server-side algorithm

        ① Call the socket() function to create a server-side connectionless socket.

        ② Call the bind() function to bind the socket to an available endpoint address of the local machine.

        ③ Call the recvfrom() function to receive data from the remote client from the socket and store it in the buffer. At the same time, obtain the remote client's socket endpoint address and save it.

        ④ Based on the saved socket endpoint address of the remote client, call the sendto() function to send the data in the buffer from the socket to the remote client.

        ⑤ After interacting with the client, call the close() function to close the socket and release the occupied system resources.

Notice:

  1. Without accept, there is no need to establish a connection;        
  2. Use recvfrom instead of read. Failure returns -1, success returns - the number of bytes read from the kernel buffer.        
  3. Use sendto instead of write. Failure returns -1, success returns - the number of bytes written to the kernel buffer.
/*server.c*/
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <ctype.h>

#define SERV_PORT 8000

int main(void)
{
    struct sockaddr_in serv_addr, clie_addr;
    socklen_t clie_addr_len;
    int sockfd;
    char buf[BUFSIZ];
    char str[INET_ADDRSTRLEN];
    int i, n;


    /* 打开一个网络通讯端口,分配一个文件描述符sockfd */
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    bzero(&serv_addr, sizeof(serv_addr)); //初始化为空
    serv_addr.sin_family = AF_INET; //地址采用IPv4地址
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); //地址从主机字节顺序转换成网络字节顺序
    serv_addr.sin_port = htons(SERV_PORT); //端口号从主机字节顺序转换成网络字节顺序

    /* 将文件描述符sockfd和服务器地址绑定 */
    bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));

    printf("Accepting connections ...\n");
    while (1) {
         /* 接收client端传过来的的字符串,写入buf */
        clie_addr_len = sizeof(clie_addr);
        n = recvfrom(sockfd, buf, BUFSIZ,0, (struct sockaddr *)&clie_addr, &clie_addr_len);
        if (n == -1)
            perror("recvfrom error");
        
        /* 打印客户端IP及端口 */
        printf("received from %s at PORT %d\n",
                inet_ntop(AF_INET, &clie_addr.sin_addr, str, sizeof(str)),
                ntohs(clie_addr.sin_port));

        /* 小写转为大写 */        
        for (i = 0; i < n; i++)
            buf[i] = toupper(buf[i]);

        /* 把数据发送给客户端 */
        n = sendto(sockfd, buf, n, 0, (struct sockaddr *)&clie_addr, sizeof(clie_addr));
        if (n == -1)
            perror("sendto error");
    }

    close(sockfd);

    return 0;
}

Client code implementation

  •  Step description of UDP client algorithm

        ① Call the socket() function to create a client-side connectionless socket.

        ② Find the IP address and protocol port number of the remote server you want to communicate with; then call the sendto() function to send the data in the buffer from the socket to the remote server.

        ③ Call the recvfrom() function to receive data from the remote server from the socket and store it in the buffer.

        ④ After interacting with the server, call the close() function to close the socket and release the occupied system resources.

Notice:

  1. There is no connect, no need to establish a connection;        
  2. Use sendto instead of write. Failure returns -1, success returns - the number of bytes written to the kernel buffer.        
  3. Use recvfrom instead of read. Failure returns -1, success returns - the number of bytes read from the kernel buffer.
/*client.c*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <ctype.h>

#define SERV_PORT 8000

int main(int argc, char *argv[])
{
    struct sockaddr_in servaddr;
    int sockfd, n;
    char buf[BUFSIZ];

    /* 打开一个网络通讯端口,分配一个文件描述符sockfd */
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    bzero(&servaddr, sizeof(servaddr)); //初始化为空
    servaddr.sin_family = AF_INET; //地址采用IPv4地址
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr); //将“点分十进制” -> “二进制整数”
    servaddr.sin_port = htons(SERV_PORT); //端口号从主机字节顺序转换成网络字节顺序

    //bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    while (fgets(buf, BUFSIZ, stdin) != NULL) {
        /* 发送给服务端 */
        n = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
        if (n == -1)
            perror("sendto error");
        
        /* 从服务端接收数据 */
        n = recvfrom(sockfd, buf, BUFSIZ, 0, NULL, 0);         //NULL:不关心对端信息
        if (n == -1)
            perror("recvfrom error");
        
        /* 输出服务器处理后的数据 */
        write(STDOUT_FILENO, buf, n);
    }

    close(sockfd);

    return 0;
}

 

 

Guess you like

Origin blog.csdn.net/weixin_43200943/article/details/130238209