socket编程 -- 基于UDP协议的C/S通信模型及实现

UDP服务端/客户端通信的基本模型

socket编程 -- 基于UDP协议的C/S通信模型及实现_第1张图片

由于UDP不需要维护连接,程序逻辑简单了很多。
但是UDP协议是不可靠的,实际上有很
多保证通讯可靠性的机制需要在应用层实现。


基于UDP协议的客户端/服务端通信的实现

服务端
接收来自客户端的字符串,将小写字母转为大写字符后发送给客户端

服务端源码server.c

/*server.c*/
#include 
#include 
#include 
#include 
#include 
#include 

#define MAXLINE 80
#define SERV_PORT 8000

int main()
{
    struct sockaddr_in servaddr, cliaddr;
    socklen_t cliaddr_len;
    int sockfd;
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];
    int i, n;

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

    bzero(&servaddr, sizeof(servaddr));//初始化为空
    servaddr.sin_family = AF_INET;//地址采用IPv4地址
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//地址从主机字节顺序转换成网络字节顺序
    servaddr.sin_port = htons(SERV_PORT);//端口号从主机字节顺序转换成网络字节顺序
    /*将文件描述符sockfd和服务器地址绑定*/
    bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    printf("等待连接...\n");
    while(1){
        cliaddr_len = sizeof(cliaddr);
        /*接收client端传过来的的字符串,写入buf*/
        n = recvfrom(sockfd, buf, MAXLINE, 0, (struct sockaddr*)&cliaddr, &cliaddr_len);
        if(n == -1){
            printf("recvfrom error");
        }
        /*打印客户端IP及端口*/
        printf("接收到来自地址为 %s 端口号为 %d 的数据\n", 
                (char*)inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
                ntohs(cliaddr.sin_port));
        /*小写转为大写*/        
        for(i = 0; itoupper(buf[i]);
        }
        /*把数据发送给客户端*/
        n = sendto(sockfd, buf, n, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
        if (n == -1){
            printf("sendto error\n");
        }
    }

    return 0;
}

客户端

客户端发送字符串给服务端,然后打印服务端传过来的数据
客户端源码client.c

/*client.c*/
#include 
#include 
#include 
#include 
#include 
#include 

#define MAXLINE 80
#define SERV_PORT 8000

int main(int argc, char *argv[])
{
    struct sockaddr_in servaddr;
    int sockfd, n;
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];
    socklen_t servaddr_len;
    /*打开一个网络通讯端口,分配一个文件描述符sockfd*/
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_famliy = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr); //将“点分十进制” -> “二进制整数”
    servaddr.sin_port = htons(SERV_PORT);//端口号从主机字节顺序转换成网络字节顺序

    while(fgets(buf, MAXLINE, stdin) != NULL){ //输入字符串
        /*发送给服务端*/
        n = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr*)&servaddr, sizeof(servaddr));
        if(n == -1)
            printf("sebdto err\n");
        /*从服务端接收数据*/
        n = recvfrom(sockfd, buf, MAXLINE, 0, NULL, 0);
        if(n == -1)
            printf("recvfrom err\n");
        /*输出服务器处理后的数据*/
        write(STDOUT_FILENO, buf, n);
    }

    close(sockfd);
    return 0;
}

编译及执行结果如下:

yu@ubuntu:~/Linux/213$ ls
client.c  server.c
yu@ubuntu:~/Linux/213$ gcc -o server server.c
yu@ubuntu:~/Linux/213$ gcc -o client client.c
yu@ubuntu:~/Linux/213$ ls
client  client.c  server  server.c
yu@ubuntu:~/Linux/213$ ./server
等待连接...
接收到来自地址为 127.0.0.1 端口号为 40245 的数据
接收到来自地址为 127.0.0.1 端口号为 40245 的数据
接收到来自地址为 127.0.0.1 端口号为 40245 的数据
接收到来自地址为 127.0.0.1 端口号为 43352 的数据
^C

另开一端口,到当期目录打开客户端,执行./client,发送三条信息后,发现服务端打印出三条相同信息。
CTRL+C后再次打开./client发送数据后发现服务端打印一条相同信息,端口号变了。

yu@ubuntu:~/Linux/213$ ./client
hey, how are you?
HEY, HOW ARE YOU?
give me your number ok?
GIVE ME YOUR NUMBER OK?
all right bye
ALL RIGHT BYE
^C
yu@ubuntu:~/Linux/213$ ./client
i do not believe love now
I DO NOT BELIEVE LOVE NOW
^C

你可能感兴趣的:(Linux,network,programming)