首页 > 解决方案 > C中的套接字:客户端无法接收和打印从服务器发送的字符串数组

问题描述

我编写套接字程序,即客户端向服务器发送一个字符串数组,服务器接收该数组并发送回客户端。我的服务器可以在服务器端成功打印出字符串数组 reply[] 。但是,在客户端,它无法打印出结果。这是我的代码

客户端.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>

#define PORT 4444

int main(int argc, char *argv[]){

    if (argc < 2 || argc > 3)      // Test for correct number of arguments
        printf("Parameter(): <Server Address>");    

    char *servIP = argv[1];        // arg: server IP address (dotted quad)
    int clientSocket, ret;
    struct sockaddr_in serverAddr; // Server address
    char buffer[1024];
    char **reply = malloc(20*sizeof(char *));

    // Create a reliable, stream socket using TCP
    clientSocket = socket(AF_INET, SOCK_STREAM, 0);
    if(clientSocket < 0){
        printf("Error in connection.\n");
        exit(1);
    }
    printf("Client Socket is created.\n");

    // Construct the server address structure
    memset(&serverAddr, '\0', sizeof(serverAddr)); // Zero out structure
    serverAddr.sin_family = AF_INET;               // IPv4 address family
    serverAddr.sin_port = htons(PORT);             // Server port
    // Convert address
    int rtnVal = inet_pton(AF_INET, servIP, &serverAddr.sin_addr.s_addr);
    if (rtnVal == 0)
        printf("inet_pton() failed: invalid address string");
    else if (rtnVal < 0)
        printf("inet_pton() failed");

    // Establish the connection to the sorted server
    ret = connect(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
    if(ret < 0){
        printf("Error in connection.\n");
        exit(1);
    }
    printf("Connected to Server.\n");

    //Read arrays from input file
    FILE *fptr;
    fptr = fopen("client1.inputdat", "r"); //open input file to read
    if (fptr != NULL)
    { 
        int line =0;
        while(fgets(buffer, sizeof(buffer), fptr)) {  //read line by line of the input file
            line++;
            if (line==1) {
                printf("\n");               
                printf("Unsorted array: %s\n", buffer);
                // Send arrays to the server
                send(clientSocket, buffer, strlen(buffer), 0);
                // Receive the sorted arrays back from the server
                if(recv(clientSocket, &reply, 20*sizeof(char *), 0) < 0){
                    printf("Error in receiving data.\n");
                }
                else {
                    int i;
                    printf("Sorted array:");
                    for (i=0; i<20; i++) {
                        reply[i] = malloc(10*sizeof(char));
                        printf("%s ", reply[i]); 
                    }
                }
            }
        }
        fclose(fptr);
    } 
    else {
        printf("File does not exits");
        exit(1);
    }
    return 0;
}

服务器.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 4444

int main(){

    int sockfd, ret;
     struct sockaddr_in serverAddr; // Local address

    int newSocket;
    struct sockaddr_in newAddr;

    socklen_t addr_size;

    char buffer[1024];
    pid_t childpid;

    // Create socket for incoming connections
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0){
        printf("Error in connection.\n");
        exit(1);
    }
    printf("Server Socket is created.\n");

    // Construct local address structure    
    memset(&serverAddr, '\0', sizeof(serverAddr));        // Zero out structure
    serverAddr.sin_family = AF_INET;                      // IPv4 address family
    serverAddr.sin_port = htons(PORT);                    // Local port
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);       // Any incoming interface

    // Bind to the local address
    ret = bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
    if(ret < 0){
        printf("Error in binding.\n");
        exit(1);
    }
    printf("Bind to port %d\n", 4444);

    // Mark the socket so it will listen for incoming connections 
    if(listen(sockfd, 10) == 0){                 //Maximum outstanding connection requests is 10
        printf("Listening....\n");
    }else{
        printf("Error in binding.\n");
    }


    while(1){
        // Wait for clients to connect
        newSocket = accept(sockfd, (struct sockaddr*)&newAddr, &addr_size);
        if(newSocket < 0){
            exit(1);
        }
        // newSocket is connected to client!
        char newName[INET_ADDRSTRLEN]; // String to contain client address
        if (inet_ntop(AF_INET, &newAddr.sin_addr.s_addr, newName, sizeof(newName)) != NULL)
            printf("Handling client %s/ %d\n", newName, ntohs(newAddr.sin_port));
        else
            printf("Unable to get client address");

        //Handle concurrency by using fork
        if((childpid = fork()) == 0){
            close(sockfd);

            while(1){
                recv(newSocket, buffer, 1024, 0);
                    int i=0;
                    char *array[20];
                    char **reply = malloc(20*sizeof(char *));
                    char *p = strtok(buffer, ",");
                    while (p!=NULL) {
                        array[i++] = p;
                        p = strtok(NULL, ","); //stroke received string into tokens
                    }
                    for (i=0; i<20; i++) {
                        reply[i] = malloc(10*sizeof(char));
                        strcpy(reply[i], array[i]); //input tokens into array
                        printf("%s ", reply[i]);
                    }

                    send(newSocket, reply, 20*sizeof(char *), 0);
                    bzero(reply, sizeof(reply));
                //}
            }
        }

    }    
    close(newSocket);
    return 0;
}

那么,我该如何解决这个问题,以便客户端可以打印出从服务器发送的数组回复 []?谢谢推荐

标签: csockets

解决方案


好的。您的代码清楚地表明您不太了解 C,更不用说套接字,但这是一个新的改进版本,我认为它可以满足您的需求。我的大部分改进都包含在对原始帖子的评论中。我没有在所有合适的地方检查错误,这在许多其他方面远非完美,但这会做一些看起来像你想要的事情而不会爆炸。

您正在发送数据,却不知道您是否收到了所有已传输的数据。套接字是流。它以最方便的方式发送数据,而不是您可能喜欢的方式。为了解决这个问题,我要求我们\n在每次传输时发送一个。\n每次从另一端取回数据时,我们都会检查并继续读取数据。在我发送了许多回复数据后,我发送了一个\n字符,以便客户端知道已收到整行。我们不需要\n从客户端添加,因为在缓冲区的末尾fgets留下了。\n

你提到排序是额外的好处,我添加了一个qsort来排序数据。在compReply函数中,我不只是直接从 the 返回值,strcmp而是将其放入 anint中,以便在必要时在调试器中看到它。我相信一些编译器会抱怨我在做strcmp两个void *变量。为了整洁,您可能希望在将它们(char*)a传递给strcmp.

我删除了您fork以使其更易于调试。抱歉,这一次只允许一个连接。当我写这样的东西时,我通常不会派生一个新进程,而是有一个 newSocket 值数组并select用来决定从哪个值读取。(该select函数也可以使用accept。)同样,这种方式更容易调试。

strtok函数将找到的字符替换为 null 并返回指向字符串开头的指针。我只是想删除不需要的字符,所以我使用它而不费心接受返回值。这也可以通过以下方式完成:

char *p=strchr(buffer,'\n');
if( NULL != p ) *p=0;

但是strtok更简洁。

我允许将端口号传递给服务器,但没有将其添加到客户端。那好吧。

我在让客户端运行之前测试了服务器

telnet 127.0.0.1 4444

并输入:a,s,d,f,g,h,j,k,l <CR> 要取回已排序的列表a,d,f,g,h,j,k,l,s, ,我也不喜欢尾随逗号,但我现在不会让它消失。

服务器:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 4444
#define BUF_SIZE 1024
static int compReply(const void *a, const void *b)
{
    int ret=strcmp(a,b);
    return(ret);
}
int main(int argc, char *argv[])
{
    int port=4444;
    int sockfd, ret;
    struct sockaddr_in serverAddr; // Local address

    int newSocket;
    struct sockaddr_in newAddr;

    socklen_t addr_size;

    if( argc > 1 ) {
        port=atoi(argv[1]);
        if( port < 1024 ) {
            port=4444;
        }
    }

    // Create socket for incoming connections
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0){
        printf("Error in connection.\n");
        exit(1);
    }
    printf("Server Socket is created.\n");

    // Construct local address structure
    memset(&serverAddr, '\0', sizeof(serverAddr));        // Zero out structure
    serverAddr.sin_family = AF_INET;                      // IPv4 address family
    serverAddr.sin_port = htons(PORT);                    // Local port
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);       // Any incoming interface

    // Bind to the local address
    ret = bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
    if(ret < 0){
        printf("Error in binding.\n");
        perror("bind");
        exit(1);
    }
    printf("Bind to port %d\n", port);

    // Mark the socket so it will listen for incoming connections
    if(listen(sockfd, 10) == 0){                 //Maximum outstanding connection requests is 10
        printf("Listening....\n");
    }else{
        printf("Error in listening.\n");
        perror("listen");
    }

    while(1){
        // Wait for clients to connect
        newSocket = accept(sockfd, (struct sockaddr*)&newAddr, &addr_size);
        if(newSocket < 0){
            exit(1);
        }
        // newSocket is connected to client!
        char newName[INET_ADDRSTRLEN]; // String to contain client address
        if (inet_ntop(AF_INET, &newAddr.sin_addr.s_addr, newName, sizeof(newName)) != NULL)
            printf("Handling client %s/ %d\n", newName, ntohs(newAddr.sin_port));
        else
            printf("Unable to get client address");

        while(1){
            char buffer[BUF_SIZE]={0};
            int ret=1;
            int count=0;
            while(NULL == strchr(buffer,'\n') && ret > 0 && count < sizeof(buffer))
            {
                ret=recv(newSocket, &buffer[count], sizeof(buffer)-count, 0);
                count+=ret;
            }
            if( ret <= 0 ) {
                if( ret < 0 ) {
                    printf("Problem with recv: %d\n", ret);
                }
                break;
            }
            printf("recv: %s\n", buffer);
            strtok(buffer,"\n\r"); /* throw away any \r\n */
            if( ret> 0 ) {
                int i=0;
                char reply[20][BUF_SIZE]={0};
                char *p = strtok(buffer, ",");
                while (p!=NULL) {
                    strncpy(reply[i],p,BUF_SIZE);
                    strcat(reply[i],",");
                    p = strtok(NULL, ","); //stroke received string into tokens
                    i++;
                }
                qsort(reply,i,BUF_SIZE,compReply);
                for(int jj=0; jj<i; jj++) {
                    printf("%s ", reply[jj]);
                    ret=send(newSocket, reply[jj], strlen(reply[jj]), 0);
                }
                ret=send(newSocket, "\n", 1, 0);
                printf("\n");
            }
        }

        close(newSocket);
    }
    return 0;
}

客户端:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>

#define PORT 4444
#define BUF_SIZE 1024

int main(int argc, char *argv[])
{
    char servIP[120]="127.0.0.1";

    if( argc > 1 ) {
        strncpy(servIP,argv[1],sizeof(servIP));
    }

    int clientSocket, ret;
    struct sockaddr_in serverAddr; // Server address
    char buffer[BUF_SIZE];

    // Create a reliable, stream socket using TCP
    clientSocket = socket(AF_INET, SOCK_STREAM, 0);
    if(clientSocket < 0){
        printf("Error in connection.\n");
        exit(1);
    }
    printf("Client Socket is created.\n");

    // Construct the server address structure
    memset(&serverAddr, '\0', sizeof(serverAddr)); // Zero out structure
    serverAddr.sin_family = AF_INET;               // IPv4 address family
    serverAddr.sin_port = htons(PORT);             // Server port
    // Convert address
    int rtnVal = inet_pton(AF_INET, servIP, &serverAddr.sin_addr.s_addr);
    if (rtnVal == 0)
        printf("inet_pton() failed: invalid address string");
    else if (rtnVal < 0)
        printf("inet_pton() failed");

    // Establish the connection to the sorted server
    ret = connect(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
    if(ret < 0){
        printf("Error in connection.\n");
        exit(1);
    }
    printf("Connected to Server.\n");

    //Read arrays from input file
    FILE *fptr;
    fptr = fopen("this.csv", "r"); //open input file to read
    if (fptr != NULL) {
        while(fgets(buffer, sizeof(buffer), fptr))    //read line by line of the input file
        {
            char reply[BUF_SIZE]={0};
            char repList[20][BUF_SIZE]={0};
            int count=0;
            int ret=1;
            printf("Unsorted array: %s", buffer);
            // Send array to the server
            send(clientSocket, buffer, strlen(buffer), 0);
            // Receive the sorted arrays back from the server
            while(NULL == strchr(reply,'\n') && ret > 0 && count < sizeof(reply))
            {
                ret=recv(clientSocket, &reply[count],sizeof(reply)-count,0);
                count+=ret;
            }
            if( ret < 0 ) {
                printf("Error in receiving data.\n");
            }
            else {
                int i=0;
                strtok(reply,"\n\r");
                for(char *p=strtok(reply,",");p!=NULL; p=strtok(NULL,","))
                {
                    strncpy(repList[i],p,BUF_SIZE);
                    i++;
                }
                printf("Sorted array:");
                for (int jj=0; jj<i; jj++) {
                    printf("%s ", repList[jj]);
                }
            }
            printf("\n");
        }
        fclose(fptr);
    }
    else {
        printf("File does not exist");
        perror("fopen");
        exit(1);
    }
    return 0;
}

这应该给你一些尝试让你继续前进。我希望它有所帮助。


推荐阅读