简体   繁体   中英

How to send result of execute command from server to client?

I'm implementing a socket program in C.

Program description:
After server and client have been connected, the client sends a command to the server.
The server receives the request from the client and executes it.
The server sends the result of the execution to the client.
The client will display that server execute and display.

My problem:
Server:
I put result of execvp() function into pipe pipefd[1] and send this data to the client with send() .
Client:
I receive recv() data to server and display.

But it doesn't work.

Result that I want:
Client : ls

Server:

a.txt b.pdf c.jpg

Client:

a.txt b.pdf c.jpg

Here is my code:

Server:

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

#define MAXPENDING 5
#define BUFFSIZE 32
#define MAX 128
void Die(char *mess) 
{
    perror(mess);
    exit(1);
}
void setup(char inputBuffer[], char *args[], int *background) //Ham xu li (cat) chuoi lenh
{
        const char s[4] = " \t\n";
        char *token;
        token = strtok(inputBuffer, s);
        int i = 0;
        while( token != NULL)
        {
            args[i] = token;
            i++;
            //printf("%s\n", token);
            token = strtok(NULL,s);
        }
        args[i] = NULL;
}
void HandeClient(int sock){

char buffer[BUFFSIZE];
int received = -1;
char data[MAX];

    data[0] = '\0';

    /*recv() from client;*/
    if((received = recv(sock, buffer,BUFFSIZE,0))<0){

        Die("Failed");
    }

    buffer[received] = '\0';

    strcat (data,  buffer);
    while(received>0)
    {
        /* send() from server; //acknowledge to client */
        if(send(sock,buffer, received,0)!= received){
            Die("Failed");
        }
        /* recv() from client; */
        if((received=recv(sock,buffer,BUFFSIZE,0))<0){
            Die("Failed");
        }

        buffer[received] = '\0';
        strcat (data, buffer);
    }

    puts (data);
    {
        char *args[100];
        setup(data,args,0);

        // pipe
        int pipefd[2],lenght;

        pipe(pipefd);

        pid_t pid = fork();
        char path[MAX];

        if(pid>0)
        {
            // parent process // write to pipe

            execvp(args[0],args);
            dup2(1,pipefd[1]);
            close(pipefd[0]);
            write(STDOUT_FILENO,pipefd[1],strlen(pipefd[1]));
            close(pipefd[1]);
            while (wait(NULL) != pid);
        }
        else
            if(pid==0)
            {
                //child process // read from pipe

                close(pipefd[1]);
                while(lenght=read(pipefd[0],path,1) > 0){
                    // send the result of execvp for client.
                    if(send(sock,path,strlen(path),0) != strlen(path) ){
                        Die("Failed");
                    }
                }
                close(pipefd[0]);
                exit(1);//
            }
            else
            {
                printf("Error !\n");
                exit(0);//
            }
    }
    if (strcmp (data, "exits")==0)
    {
        exit (1);
    }
    close(sock);
}
int main(int argc, char const *argv[])
{
    int serversock,clientsock;
    struct sockaddr_in echoserver, echoclient;
    /*if(argc !=2)
    {
        fprintf(stderr, "USAGE: echoserver <port>\n");
        exit(0);
    }*/
    if((serversock = socket(PF_INET, SOCK_STREAM,IPPROTO_TCP))<0){
        Die("Failed");
    }
    memset(&echoserver,0,sizeof(echoserver));
    echoserver.sin_family = AF_INET;
    echoserver.sin_addr.s_addr= htonl(INADDR_ANY);
    echoserver.sin_port = htons(atoi(argv[1]));

    if(bind(serversock, (struct sockaddr *) & echoserver,sizeof(echoserver))<0){
        Die("Failed");
    }
    if(listen(serversock,MAXPENDING)<0){
        Die("Failed");
    }
    while(1)
    {
        unsigned int clientlen = sizeof(echoclient);
        if((clientsock = 
            accept(serversock,(struct sockaddr *) &echoclient,
                                &clientlen))<0){
            Die("Failed");
        }
        fprintf(stdout, "Client connected: %s\n",
                        inet_ntoa(echoclient.sin_addr));
        fprintf(stdout,"Message from client:");
        HandeClient(clientsock);        
    }

    return 0;
}

Client:

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#define BUFFSIZE 32
/// Client chuyen mot chuoi ki tu, sau khi an enter n gui cho server roi ket thuc
void Die(char *mess) 
{
    perror(mess); 
    exit(1); 
}
int main(int argc, char *argv[]) 
{
while(1){
    int sock;
    struct sockaddr_in echoserver;
    char buffer[BUFFSIZE];
    unsigned int echolen;
    int received = 0;
    if (argc != 3) 
    {
        fprintf(stderr, "USAGE: TCPecho <server_ip> <word> <port>\n");
        exit(1);
    }
/* Create the TCP socket */
    if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 
    {
        Die("Failed to create socket");
    }
/* Construct the server sockaddr_in structure */
    memset(&echoserver, 0, sizeof(echoserver));
    echoserver.sin_family = AF_INET;
    echoserver.sin_addr.s_addr = inet_addr(argv[1]);
    echoserver.sin_port = htons(atoi(argv[2]));
/* Establish connection */
    if (connect(sock,(struct sockaddr *) &echoserver,sizeof(echoserver)) < 0) 
    {
        Die("Failed to connect with server");
    }
/* Send the word to the server */
    //tao mot chuoi s, chuoi s nhan ki tu tu ban phim, roi chuyen cho phia server
    char s[100];
    fgets(s,100,stdin);
    echolen = strlen(s);

    /*  send() from client; */
    if (send(sock, s, echolen, 0) != echolen) 
    {
        Die("Mismatch in number of sent bytes");
    }
/* Receive the word back from the server */
    fprintf(stdout, "Message from server: ");
    while (received < echolen) 
    {
        int bytes = 0;
        /* recv() from server; */
        if ((bytes = recv(sock, buffer, BUFFSIZE-1, 0)) < 1) 
        {
            Die("Failed to receive bytes from server");
        }
        received += bytes;
        buffer[bytes] = '\0';
        /* Assure null terminated string */
        fprintf(stdout, buffer);
    }

    fprintf(stdout, "\n");
    close(sock);
    if(strcmp(s,"exit") == 0)
    exit(0);
}
}

I modified the code to what I believe is your intended behavior. Note that execvp() is being executed at the end instead of the beginning as in your original code. I fixed a few places where both server and client were attempting to receive when one of them should be sending.

I added while loop to allow executing commands until client types exit.

Please see the comments within the code.

Server

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

#define MAXPENDING 5
#define BUFFSIZE 2048
#define MAX 2048
void Die(char *mess) 
{
    perror(mess);
    exit(1);
}

void setup(char inputBuffer[], char *args[], int *background) //Ham xu li (cat) chuoi lenh
{
    const char s[4] = " \t\n";
    char *token;
    token = strtok(inputBuffer, s);
    int i = 0;
    while( token != NULL)
    {
        args[i] = token;
        i++;
        //printf("%s\n", token);
        token = strtok(NULL,s);
    }
    args[i] = NULL;
}

void HandeClient(int sock){

char buffer[BUFFSIZE];
int received = -1;
char data[MAX];
memset(data,0,MAX);

while(1) { // this will make server wait for another command to run until it receives exit
    data[0] = '\0';
    if((received = recv(sock, buffer,BUFFSIZE,0))<0){

        Die("Failed");
    }

    buffer[received] = '\0';

    strcat (data,  buffer);
    if (strcmp(data, "exit")==0) // this will force the code to exit
        exit(0);
/* This block causes server to wait for more data from client when all data are already received.
    while(received>0)
    {
        if(send(sock,buffer, received,0)!= received){
            Die("Failed");
        }
        if((received=recv(sock,buffer,BUFFSIZE,0))<0){
            Die("Failed");
        }

        buffer[received] = '\0';
        strcat (data, buffer);
    }
*/

    puts (data);
        char *args[100];
        setup(data,args,0);
        int pipefd[2],lenght;

        if(pipe(pipefd))
            Die("Failed to create pipe");

        pid_t pid = fork();
        char path[MAX];

        if(pid==0)
        {
            close(1); // close the original stdout
            dup2(pipefd[1],1); // duplicate pipfd[1] to stdout
            close(pipefd[0]); // close the readonly side of the pipe
            close(pipefd[1]); // close the original write side of the pipe
            execvp(args[0],args); // finally execute the command
        }
        else
            if(pid>0)
            {
                close(pipefd[1]);
                memset(path,0,MAX);
                while(lenght=read(pipefd[0],path,MAX-1)){
                    printf("Data read so far %s\n", path);
                    if(send(sock,path,strlen(path),0) != strlen(path) ){
                        Die("Failed");
                    }
                    fflush(NULL);
                    printf("Data sent so far %s\n", path);
                memset(path,0,MAX);
                }
                close(pipefd[0]);
                //exit(1); removed so server will not terminate
            }
            else
            {
                printf("Error !\n");
                exit(0);//
            }
}
/*
    if (strcmp (data, "exit")==0)
    {
        exit (1);
    }
    printf("Closing socket\n");
    close(sock);
*/
}

int main(int argc, char const *argv[])
{
    int serversock,clientsock;
    struct sockaddr_in echoserver, echoclient;
    unsigned int clientlen = sizeof(echoclient);
    signal(SIGPIPE, SIG_IGN); // this will allow code to handle SIGPIPE instead of crashing
    if((serversock = socket(PF_INET, SOCK_STREAM,IPPROTO_TCP))<0){
        Die("Failed");
    }
    memset(&echoserver,0,sizeof(echoserver));
    echoserver.sin_family = AF_INET;
    echoserver.sin_addr.s_addr= htonl(INADDR_ANY);
    echoserver.sin_port = htons(atoi(argv[1]));

    if(bind(serversock, (struct sockaddr *) & echoserver,sizeof(echoserver))<0){
        Die("Failed");
    }
    if(listen(serversock,MAXPENDING)<0){
        Die("Failed");
    }
    while(1)
    {
        if((clientsock = 
            accept(serversock,(struct sockaddr *) &echoclient,
                                &clientlen))<0){
            Die("Failed");
        }
        fprintf(stdout, "Client connected: %s\n",
                        inet_ntoa(echoclient.sin_addr));
        fprintf(stdout,"Message from client:");
        HandeClient(clientsock);        
    }

    return 0;
}

Client

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

    void Die(char *mess) 
    {
        perror(mess); 
        exit(1); 
    }
    int main(int argc, char *argv[]) 
    {
        int sock;
        struct sockaddr_in echoserver;
        char buffer[BUFFSIZE];
        unsigned int echolen;
        int received = 0;
        if (argc != 3) 
        {
            fprintf(stderr, "USAGE: TCPecho <server_ip> <word> <port>\n");
            exit(1);
        }
        if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 
        {
            Die("Failed to create socket");
        }
        memset(&echoserver, 0, sizeof(echoserver));
        echoserver.sin_family = AF_INET;
        echoserver.sin_addr.s_addr = inet_addr(argv[1]);
        echoserver.sin_port = htons(atoi(argv[2]));
        if (connect(sock,(struct sockaddr *) &echoserver,sizeof(echoserver)) < 0) 
        {
            Die("Failed to connect with server");
        }
        char s[100];
    while(1) { // to repeat the whole process until exit is typed
        fgets(s,100,stdin);
        s[strlen(s)-1]='\0'; //fgets doesn't automatically discard '\n'
        echolen = strlen(s);

        /*  send() from client; */
        if (send(sock, s, echolen, 0) != echolen) 
        {
            Die("Mismatch in number of sent bytes");
        }
        if(strcmp(s,"exit") == 0) // check if exit is typed
        exit(0);
        fprintf(stdout, "Message from server: ");
        while (received < echolen) 
        {
            int bytes = 0;
            /* recv() from server; */
            if ((bytes = recv(sock, buffer, echolen, 0)) < 1) 
            {
                Die("Failed to receive bytes from server");
            }
            received += bytes;
            buffer[bytes] = '\0';
            /* Assure null terminated string */
            fprintf(stdout, buffer);
        }
        int bytes = 0;
// this d {...} while block will receive the buffer sent by server
        do {
            buffer[bytes] = '\0';
            printf("%s\n", buffer);
        } while((bytes = recv(sock, buffer, BUFFSIZE-1, 0))>=BUFFSIZE-1);
        buffer[bytes] = '\0';
        printf("%s\n", buffer);
        printf("\n");
    }
    }

There isn't any need to loop the client because the server exits after sending back the result.

You've got a segmentation fault on this line because you're attempting to pass an integer to strlen :

write(STDOUT_FILENO,pipefd[1],strlen(pipefd[1]));

Your compiler should emit at least a warning for this; gcc does:

server.c:84: warning: passing argument 1 of 'strlen' makes pointer from integer without a cast
/usr/include/string.h:399: note: expected 'const char *' but argument is of type 'int'

If the intention was to write the value of pipefd[1] to STDOUT_FILENO as a binary integer then did you mean to do this?

write(STDOUT_FILENO,&pipefd[1],sizeof(pipefd[1]));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM