zoukankan      html  css  js  c++  java
  • 网络编程——实现迭代服务器端/客户端

    基于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;
    }

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

                                                                                                                       

  • 相关阅读:
    Working with macro signatures
    Reset and Clear Recent Items and Frequent Places in Windows 10
    git分支演示
    The current .NET SDK does not support targeting .NET Core 2.1. Either target .NET Core 2.0 or lower, or use a version of the .NET SDK that supports .NET Core 2.1.
    Build website project by roslyn through devenv.com
    Configure environment variables for different tools in jenkins
    NUnit Console Command Line
    Code Coverage and Unit Test in SonarQube
    头脑王者 物理化学生物
    头脑王者 常识,饮食
  • 原文地址:https://www.cnblogs.com/bencai/p/9520168.html
Copyright © 2011-2022 走看看