如何将执行命令的结果从服务器发送到客户端?

时间:2015-11-04 07:47:28

标签: c linux sockets

我正在用C实现套接字程序。

节目说明:
连接服务器和客户端后,客户端向服务器发送命令 服务器从客户端接收请求并执行它 服务器将执行结果发送给客户端 客户端将显示该服务器的执行和显示。

我的问题:
服务器:我将execvp()功能的结果放入管道pipefd[1],然后将此数据发送给send()的客户端。
客户端:
我收到recv()数据到服务器并显示。

但它不起作用。

我想要的结果:
客户 ls

服务器:

  

a.txt b.pdf c.jpg

客户端:

  

a.txt b.pdf c.jpg

这是我的代码:

服务器

#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;
}

客户端:

#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);
}
}

2 个答案:

答案 0 :(得分:1)

我将代码修改为我认为是您的预期行为。请注意,execvp()正在执行,而不是原始代码中的开头。我修复了服务器和客户端试图接收其中一个应该发送的几个地方。

我添加了while循环以允许执行命令,直到客户端类型退出。

请参阅代码中的注释。

服务器

#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;
}

<强>客户端

    #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");
    }
    }

没有必要循环客户端,因为服务器在发回结果后退出。

答案 1 :(得分:0)

您在此行上遇到分段错误,因为您尝试将整数传递给strlen

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

您的编译器应至少发出一个警告; gcc确实:

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'

如果打算将pipefd[1]的值写为STDOUT_FILENO作为二进制整数,那么您的意思是这样做吗?

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