• 网络编程——实现迭代服务器端/客户端


    基于TCP的服务端编程——实现一个简单的回声服务器端/客户端。即服务器端将客户端传输的字符串数据原封不动地传回客户端,就像回声一样。

    服务端:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <arpa/inet.h>
    #include <sys/socket.h>
    #define BUF_SIZE 1024
    
    void ErrorHandling(char *message) {
        fputs(message, stderr);
        fputs("
    ", stderr);
        exit(1);
    }
    
    int main(int argc, char * argv[]) {
        int serv_sock, clnt_sock;
        char message[BUF_SIZE];
        int str_len, i;
    
        struct sockaddr_in serv_adr, clnt_adr;
        socklen_t clnt_adr_sz;
    
        if(argc != 2) {
            printf("Usage : %s <port>
    ", argv[0]);
            exit(1);
        }
    
        serv_sock  = socket(PF_INET, SOCK_STREAM, 0);
        if (serv_sock == -1)
            ErrorHandling("socket() error!");
    
        memset(&serv_adr, 0, sizeof(serv_adr));
        serv_adr.sin_family = AF_INET;
        serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
        serv_adr.sin_port = htons(atoi(argv[1]));
    
        if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1)
            ErrorHandling("bind() error!");
    
        if(listen(serv_sock, 5) == -1)
            ErrorHandling("listen() error!");
    
        clnt_adr_sz = sizeof(clnt_adr);
        for(int i = 0; i < 5; ++i)
        {
            clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);
            if (clnt_sock == -1)
                ErrorHandling("accept() error!");
            else
                printf("Connected client %d 
    ", i + 1);
            while ((str_len = read(clnt_sock, message, BUF_SIZE)) != 0)
                write(clnt_sock, message, str_len);
    
            close(clnt_sock);
        }
        close(serv_sock);
        return 0;
    }

     客户端:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <arpa/inet.h>
    #include <sys/socket.h>
    #define BUF_SIZE 1024
    
    void ErrorHandling(char *message) {
        fputs(message, stderr);
        fputs("
    ", stderr);
        exit(1);
    }
    
    int main(int argc, char *argv[]) {
        int sock;
        char message[BUF_SIZE];
        int str_len;
        struct sockaddr_in serv_adr;
    
        if (argc != 3) {
            printf("Usage: %s <IP> <port>
    ", argv[0]);
            exit(1);
        }
    
        sock = socket(PF_INET, SOCK_STREAM, 0);
        if(sock == -1)
            ErrorHandling("socket() error!");
    
        memset(&serv_adr, 0, sizeof(serv_adr));
        serv_adr.sin_family = AF_INET;
        serv_adr.sin_addr.s_addr = inet_addr(argv[1]);
        serv_adr.sin_port = htons(atoi(argv[2]));
    
        if (connect(sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1)
            ErrorHandling("connect() error!");
        else
            printf("Connected.......
    ");
    
        while(1){
            fputs("Input message(Q to quit): ", stdout);
            fgets(message, BUF_SIZE, stdin);
    
            if(!strcmp(message,"q
    ") || !strcmp(message,"Q
    "))
                break;
    
            write(sock,message,strlen(message));
            str_len = read(sock,message,BUF_SIZE-1);
            message[str_len]=0;
            printf("Message from server: %s
    ", message);
        }
        close(sock);
        return 0;
    } 

     回声客户端存在的问题:

    write(sock,message,strlen(message));
    str_len = read(sock,message,BUF_SIZE-1);
    message[str_len]=0;
    printf("Message from server: %s
    ", message);

    由于TCP不存在数据边界,因此多次调用write()函数传递的字符串就有可能一次性传递到服务器端。此时客户端有可能从服务器端收到多个字符串。同时,服务器端希望通过调用1次write函数传输数据,但如果数据太大,操作系统就有可能把数据分成多个数据包发送到客户端。另外,在此过程中,客户端有可能在尚未收到全部数据包时就调用read函数。

    解决方法:提前确认接收数据的大小。若之前传输了20个字节,则在接受接收时循环调用read函数读取20个字节即可。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <arpa/inet.h>
    #include <sys/socket.h>
    #define BUF_SIZE 1024
    
    void ErrorHandling(char *message) {
        fputs(message, stderr);
        fputs("
    ", stderr);
        exit(1);
    }
    
    int main(int argc, char *argv[]) {
        int sock;
        char message[BUF_SIZE];
        int str_len, recv_len, recv_cnt;
        struct sockaddr_in serv_adr;
    
        if (argc != 3) {
            printf("Usage: %s <IP> <port>
    ", argv[0]);
            exit(1);
        }
    
        sock = socket(PF_INET, SOCK_STREAM, 0);
        if (sock == -1)
            ErrorHandling("socket() error!");
    
        memset(&serv_adr, 0, sizeof(serv_adr));
        serv_adr.sin_family = AF_INET;
        serv_adr.sin_addr.s_addr = inet_addr(argv[1]);
        serv_adr.sin_port = htons(atoi(argv[2]));
    
        if (connect(sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1)
            ErrorHandling("connect() error!");
        else
            printf("Connected.......
    ");
    
        while (1) {
            fputs("Input message(Q to quit): ", stdout);
            fgets(message, BUF_SIZE, stdin);
    
            if (!strcmp(message, "q
    ") || !strcmp(message, "Q
    "))
                break;
    
            str_len = write(sock, message, strlen(message));
    
        recv_len = 0;
            //while循环确保接受到服务器端传输的所有数据
            while (recv_len != str_len) {
                recv_cnt = read(sock, message, BUF_SIZE - 1);
                if (recv_cnt == -1)
                    ErrorHandling("read error");
                recv_len += recv_cnt;
            }
            message[recv_len] = 0;
            printf("Message from server: %s", message);
        }
        close(sock);
        return 0;
    }

    代码中的函数原型都很简单,就不展开解释了。

                                                                                                                       

  • 相关阅读:
    Mysql练习#1-建表
    Mysql学习笔记#7-范式
    Git学习笔记#9-标签
    Git学习笔记#8-操作冲突
    Git学习笔记#7-分支操作
    Git学习笔记#6-远程仓库(GitHub)
    Git学习笔记#5-文件删除
    Git学习笔记#4-版本回退
    Git学习笔记#3-修改文件与撤销
    免费分享老男孩全栈9期视频,共126天
  • 原文地址:https://www.cnblogs.com/bencai/p/9520168.html
Copyright © 2020-2023  润新知