主頁 > 軟體工程 > 在按下Enter之前,執行緒函式不會終止

在按下Enter之前,執行緒函式不會終止

2022-05-23 13:14:08 軟體工程

以下代碼(最后)表示執行緒函式,它從遠程客戶端接收 ls 命令并將當前作業目錄發送到該客戶端。

它成功發送但有一個問題:當它完全停止發送時,我希望它再次開始收聽。在線:

printf("Enter 1 if you want to exit or 0 if you don't: "); 
                 fgets(exit_status,MAX_SIZE,stdin);

當我按 Enter 時,它卡住并終止(并啟動另一個執行緒)

我不明白為什么?當我除錯時,我看到上面的列印陳述句在按 Enter 后執行,盡管除錯器位于函式的末尾(意味著它通過了這個列印陳述句)。

我希望它在完成發送資料后自動重新開始收聽。

如果有人想查看我的完整代碼,請點擊以下鏈接:https ://pastebin.com/9UmTkPge

void  *server_socket_ls(void *arg) {
    int* exit_status = (int*)malloc(sizeof(int));
    *exit_status = 0;   
    while (*exit_status == 0) {
    //socket code is here
        
    //code for ls
        
    char buffer[BUFFSIZE];
    int received = -1;
    char data[MAX];
    memset(data,0,MAX);
       // this will make server wait for another command to run until it receives exit
        data[0] = '\0';
        if((received = recv(new_socket, buffer,BUFFSIZE,0))<0){
    
            perror("Failed");
        }
    
        buffer[received] = '\0';
    
        strcat (data,  buffer);
        if (strcmp(data, "exit")==0) // this will force the code to exit
            exit(0);
    
        puts (data);
            char *args[100];
            setup(data,args,0);
            int pipefd[2],lenght;
    
            if(pipe(pipefd))
                perror("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(new_socket,path,strlen(path),0) != strlen(path) ){
                            perror("Failed");
                        }
                        //fflush(NULL);
                        printf("Data sent so far %s\n", path);
                        memset(path,0,MAX);
                        
                    }
    
                    close(pipefd[0]);
                    //removed so server will not terminate
                              
                }
                else 
                {
                    printf("Error !\n");
                    exit(0);
                }
                 printf("Enter 1 if you want to exit or 0 if you don't: "); 
                 fgets(exit_status,MAX_SIZE,stdin);    
                
        }
    
    }

uj5u.com熱心網友回復:

很多錯誤:

  1. In terminal_thread,input_command是在每次回圈迭代時分配的——記憶體泄漏
  2. 去除換行符的代碼被破壞
  3. 使用.l指定 IP 地址會導致段錯誤,token因為NULL
  4. terminal_threadfor中的埠號.l是 5126與對應服務器代碼中的 9191不匹配
  5. 連接后,server_socket_file什么都不做。
  6. server_socket_ls中,它和上回圈回圈應該在之后開始在回圈中執行并重監聽套接字)。socketbindlistenacceptlistenaccept
  7. 代碼中標記的其他錯誤

我不得不重構代碼并添加一些除錯。它帶有錯誤注釋。我使用cpp條件來表示舊代碼與新代碼:

#if 0
// old code
#else
// new code
#endif

#if 1
// new code
#endif

這是代碼。我得到了最小的 .l(遠程ls)作業:

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

#define BACKLOG 10
#define MAX_SIZE 200
#define BACKLOG 10
#define BUFFSIZE 2048
#define MAXPENDING 5
#define MAX 2048

__thread char *tid;
__thread char dbgstrbuf[1000];

FILE *xfdbg;

typedef struct server_arg {
    int portNum;
} server_arg;
typedef struct server_arg1 {
    int portNum;
} server_arg1;

void
dbgprt(const char *fmt,...)
{
    va_list ap;
    char msg[1000];
    char *bp = msg;

    bp  = sprintf(bp,"%4s ",tid);
    va_start(ap,fmt);
    bp  = vsprintf(bp,fmt,ap);
    va_end(ap);

    fputs(msg,xfdbg);
}

const char *
dbgstr(const char *str)
{
    char *bp = dbgstrbuf;

    bp  = sprintf(bp,"'");

    for (int chr = *str  ;  chr != 0;  chr = *str  ) {
        if ((chr > 0x20) && (chr <= 0x7E))
            bp  = sprintf(bp,"%c",chr);
        else
            bp  = sprintf(bp,"{%2.2X}",chr);
    }

    bp  = sprintf(bp,"'");

    return dbgstrbuf;
}

void
setup(char inputBuffer[], char *args[], int *background)
{
    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 *
terminal_thread(void *arg)
{
// NOTE/FIX: do this _once_
#if 1
    char *input_command = malloc(MAX_SIZE);
#endif

    tid = "term";

    while (1) {
        dbgprt("term: PROMPT\n");

        printf(">> ");
//memset(input_command,0,strlen(str));
// NOTE/BUG: this is a memory leak
#if 0
        char *input_command = malloc(MAX_SIZE);
#endif

        dbgprt("term: FGETS\n");
        fgets(input_command, MAX_SIZE, stdin);

// NOTE/BUG: code is broken to strip newline
#if 0
        if ((strlen(input_command) > 0) &&
            (input_command[strlen(input_command) - 1] == '\n'))
            input_command[strlen(input_command) - 1] = '\0';
#else
        input_command[strcspn(input_command,"\n")] = 0;
#endif

        dbgprt("term: COMMAND %s\n",dbgstr(input_command));

        char list[] = "ls";
        char cp[] = "cp";

#if 0
        char s[100];
        printf("%s\n", getcwd(s,100));
        chdir("Desktop");
        printf("%s\n", getcwd(s,100));
#endif

        if (strcmp(input_command, list) == 0) {
            // ls code will run here

        }

        if (strchr(input_command, '.') != NULL &&
            strchr(input_command, 'l') != NULL) {

            printf("remote ls\n");
            char ip[20];
            const char c[2] = " ";

            // strcpy(str,input_command);
            char *token;

            // get the first token
            token = strtok(input_command, c);

            // walk through other tokens
            int i = 0;

            while (token != NULL && i != -1) {
                token = strtok(NULL, c);
                i--;
            }
// NOTE/FIX: after the loop token _must_ be
#if 1
            if (token == NULL) {
                token = "127.0.0.1";
                printf("no IP address found -- using %s\n",token);
            }
#endif
            strcpy(ip, token);

            int sock;
            struct sockaddr_in echoserver;
            char buffer[BUFFSIZE];
            unsigned int echolen;
            int received = 0;

            if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
                perror("Failed to create socket");
                exit(1);
            }
            int enable = 1;

            if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable,
                sizeof(int)) < 0) {
                perror("error");
            }
            memset(&echoserver, 0, sizeof(echoserver));
            echoserver.sin_family = AF_INET;
            echoserver.sin_addr.s_addr = inet_addr(ip);

// NOTE/BUG: this port number does _not_ match any server port
#if 0
            echoserver.sin_port = htons(5126);
#else
            unsigned short port = 9191;
            dbgprt("term: port=%u\n",port);
            echoserver.sin_port = htons(port);
#endif

            if (connect(sock, (struct sockaddr *) &echoserver,
                sizeof(echoserver)) < 0) {
                perror("Failed to connect with server");
                exit(1);
            }
            char s[100];

            // while(1) { // to repeat the whole process until exit is typed
            strcpy(s, "ls");

// NOTE/BUG: this blows away the "s" in "ls" because s is _set_ with strcpy
#if 0
            s[strlen(s) - 1] = '\0';    // fgets doesn't automatically discard '\n'
#endif
            echolen = strlen(s);

            /* send() from client; */
            if (send(sock, s, echolen, 0) != echolen) {
                perror("Mismatch in number of sent bytes");
            }

            fprintf(stdout, "Message from server: ");

            int bytes = 0;

            /* recv() from server; */
            if ((bytes = recv(sock, buffer, echolen, 0)) < 1) {
                perror("Failed to receive bytes from server");
            }
            received  = bytes;
            buffer[bytes] = '\0';
            /* Assure null terminated string */
            fprintf(stdout, buffer);

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

            continue;
        }
    }
}

void *
server_socket_ls(void *arg)
{
    int *exit_status = (int *) malloc(sizeof(int));

    tid = "ls";

    dbgprt("ls: ENTER\n");

    *exit_status = 0;
    while (*exit_status == 0) {
        server_arg *s = (server_arg *) arg;
        int server_fd, new_socket;
        struct sockaddr_in address;
        int addrlen = sizeof(address);

        dbgprt("ls: SOCKET\n");

        // Creating socket file descriptor
        if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
            perror("socket failed");
            exit(EXIT_FAILURE);
        }
        int enable = 1;

        if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &enable,
            sizeof(int)) < 0) {
            perror("error");
        }

        address.sin_family = AF_INET;
        address.sin_addr.s_addr = INADDR_ANY;
        address.sin_port = htons(s->portNum);

        dbgprt("ls: BIND prtNum=%u\n",s->portNum);
        if (bind(server_fd, (struct sockaddr *) &address, sizeof(address))
            < 0) {
            perror("bind failed");
        }

        dbgprt("ls: LISTEN\n");
        if (listen(server_fd, 3) < 0) {
            perror("listen");
        }

        if ((new_socket = accept(server_fd, (struct sockaddr *) &address,
            (socklen_t *) & addrlen)) < 0) {
            perror("accept");
        }

        dbgprt("ls: ACCEPTED\n");
        printf("Server Connected\n");

//code for ls

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

        memset(data, 0, MAX);
        // this will make server wait for another command to run until it
        // receives exit
        data[0] = '\0';

        if ((received = recv(new_socket, buffer, BUFFSIZE, 0)) < 0) {
            perror("Failed");
        }

        buffer[received] = '\0';

        strcat(data, buffer);
        dbgstr(data);
        if (strcmp(data, "exit") == 0)  // this will force the code to exit
            exit(0);

        puts(data);
        char *args[100];

        setup(data, args, 0);
        int pipefd[2],
         lenght;

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

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

        if (pid == 0) {
// NOTE/BUG: no need to close before dup2
#if 0
            close(1);                   // close the original stdout
#endif
            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);

// NOTE/BUG: read does _not_ terminate buffer with EOS (0x00)
#if 0
            while (lenght = read(pipefd[0], path, MAX - 1)) {
                printf("Data read so far %s\n", path);
                if (send(new_socket, path, strlen(path), 0) != strlen(path)) {
                    perror("Failed");
                }
                // fflush(NULL);
                printf("Data sent so far %s\n", path);
                memset(path, 0, MAX);
            }
#else
            while (lenght = read(pipefd[0], path, MAX - 1)) {
                printf("Data read so far ", path);
                fwrite(path,1,lenght,stdout);
                printf("\n");

                if (send(new_socket, path, lenght, 0) != lenght) {
                    perror("Failed");
                }

                // fflush(NULL);
                printf("Data send so far ", path);
                fwrite(path,1,lenght,stdout);
                printf("\n");

                memset(path, 0, MAX);
            }
#endif

            // close(pipefd[0]);
            // removed so server will not terminate
// NOTE/BUG: child needs to terminate -- otherwise, _both_ parent and child
// will prompt user below
#if 1
            exit(0);
#endif

        }
        else {
            printf("Error !\n");
            exit(0);
        }

        printf("Enter 1 if you want to exit or 0 if you don't: ");
// NOTE/BUG: need to pass buffer
// NOTE/BUG: exit_status is an int pointer
#if 0
        fgets(exit_status, MAX_SIZE, stdin);
#else
        char exit_buf[100];
        fgets(exit_buf,sizeof(exit_buf),stdin);
        *exit_status = atoi(exit_buf);
#endif
    }

}

void *
server_socket_file(void *arg)
{

    tid = "file";

    dbgprt("file: ENTER\n");

    server_arg1 *s1 = (server_arg1 *) arg;
    int server_fd, new_socket;
    struct sockaddr_in address;
    int addrlen = sizeof(address);

    // Creating socket file descriptor
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
    int enable = 1;

    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int))
        < 0) {
        perror("error");
    }

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(s1->portNum);

    dbgprt("file: BIND portNum=%u\n",s1->portNum);

    if (bind(server_fd, (struct sockaddr *) &address, sizeof(address)) < 0) {
        perror("bind failed");

    }
    if (listen(server_fd, 3) < 0) {
        perror("listen");
    }

    if ((new_socket = accept(server_fd, (struct sockaddr *) &address,
        (socklen_t *) & addrlen)) < 0) {
        perror("accept");
    }

    printf("Server Connected\n");
}

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

    tid = "main";

    server_arg *s = (server_arg *) malloc(sizeof(server_arg));
    server_arg1 *s1 = (server_arg1 *) malloc(sizeof(server_arg1));
    pthread_t id_1;
    pthread_t id_2;
    pthread_t id_3;

    xfdbg = fopen("debug.txt","w");
    setlinebuf(xfdbg);

    if (pthread_create(&id_3, NULL, terminal_thread, NULL) != 0) {
        perror("pthread_create");
    }

// NOTE/BUG: this port (or the one below) doesn't match the client code
// port of 5126
    s->portNum = 9191;
    pthread_create(&id_1, NULL, server_socket_ls, s);

    s1->portNum = 6123;
    pthread_create(&id_2, NULL, server_socket_file, s1);

    pthread_join(id_1, NULL);
    pthread_join(id_2, NULL);
    pthread_join(id_3, NULL);

// NOTE/BUG: pthread_exit in main thread is wrong
#if 0
    pthread_exit(0);
#else
    return 0;
#endif
}

這是程式輸出(對于.l):

>> remote ls
no IP address found -- using 127.0.0.1
Message from server: Server Connected
ls
Data read so far debug.txt
orig
orig.c
orig.txt
out

Data send so far debug.txt
orig
orig.c
orig.txt
out

bug.txt
orig
orig.c
orig.txt
out

這是debug.txt輸出:

term term: PROMPT
term term: FGETS
  ls ls: ENTER
  ls ls: SOCKET
file file: ENTER
  ls ls: BIND prtNum=9191
file file: BIND portNum=6123
  ls ls: LISTEN
term term: COMMAND '.l'
term term: port=9191
  ls ls: ACCEPTED
term term: PROMPT

該程式在 exit(0) 停止發送資料后立即退出,因此不要求 exit_status。有沒有辦法讓它不停止,而是終端提示與在后面監聽的服務器一起重新出現?– 德拉古特

因為我感覺到了緊迫性,所以我錯誤地認為現在部分解決方案比完美解決方案為時已晚。

exit我可能在 ls 服務器父行程中引入了一個帶有無關呼叫的錯誤(現已修復)。

但是,還有其他問題...

主要問題是服務器(對于 ls )正在提示用戶是否繼續(on stdout/stdin)。這不太好用。

應該提示用戶的是客戶端(即)。terminal_thread或者,正如我所做的那樣,客戶端將exit在命令提示符下看到,然后包含“exit”的資料包發送到服務器,然后終止。然后,服務器將看到此命令并終止。

我在沒有完全重做所有內容的情況下盡可能多地重構。

我將一些代碼拆分為函式。一些可以/可以重用來實作“檔案”服務器。

但是,我會將這兩個函式都放在一個服務器執行緒中。我會讓服務器查看它獲得的“命令”并根據命令執行任一操作。由于在“檔案”服務器中沒有實際做某事的代碼 [然而] 很難返工。

要解決的一件事[我沒有時間]:

.l命令的格式為:.l [ip_address]. 的默認ip_address值為127.0.0.1但是,這應該分為兩個命令(例如):

  1. 附加 [ip_address]
  2. ls [ls 引數]

無論如何,這是更新的代碼。我不得不快一點移動,所以它沒有我想要的那么干凈。

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

#if 1
#include <time.h>
#endif

#define BACKLOG 10
#define MAX_SIZE 200
#define BACKLOG 10
#define BUFFSIZE 2048
#define MAXPENDING 5
#define MAX 2048

__thread char *tid;
__thread char dbgstrbuf[1000];

FILE *xfdbg;
double tsczero = 0.0;

typedef struct server_arg {
    int portNum;
} server_arg;
typedef struct server_arg1 {
    int portNum;
} server_arg1;

double
tscgetf(void)
{
    struct timespec ts;
    double sec;

    clock_gettime(CLOCK_MONOTONIC,&ts);

    sec = ts.tv_nsec;
    sec /= 1e9;
    sec  = ts.tv_sec;

    sec -= tsczero;

    return sec;
}

void
dbgprt(const char *fmt,...)
{
    va_list ap;
    char msg[1000];
    char *bp = msg;

    bp  = sprintf(bp,"[%.9f/%4s] ",tscgetf(),tid);
    va_start(ap,fmt);
    bp  = vsprintf(bp,fmt,ap);
    va_end(ap);

    fputs(msg,xfdbg);
}

const char *
dbgstr(const char *str,int len)
{
    char *bp = dbgstrbuf;

    if (len < 0)
        len = strlen(str);

    bp  = sprintf(bp,"'");

    for (int i = 0;  i < len;    i) {
        int chr = str[i];
        if ((chr > 0x20) && (chr <= 0x7E))
            bp  = sprintf(bp,"%c",chr);
        else
            bp  = sprintf(bp,"{%2.2X}",chr);
    }

    bp  = sprintf(bp,"'");

    return dbgstrbuf;
}

void
setup(char inputBuffer[], char *args[], int *background)
{
    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;
}

int
open_remote(const char *ip,unsigned short port)
{
    int sock;
    struct sockaddr_in echoserver;

    dbgprt("open_remote: ENTER ip=%s port=%u\n",dbgstr(ip,-1),port);

    if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
        perror("Failed to create socket");
        exit(1);
    }
    int enable = 1;

    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable,
        sizeof(int)) < 0) {
        perror("error");
    }
    memset(&echoserver, 0, sizeof(echoserver));
    echoserver.sin_family = AF_INET;
    echoserver.sin_addr.s_addr = inet_addr(ip);

// NOTE/BUG: this port number does _not_ match any server port
#if 0
    echoserver.sin_port = htons(5126);
#else
    dbgprt("term: port=%u\n",port);
    echoserver.sin_port = htons(port);
#endif

    if (connect(sock, (struct sockaddr *) &echoserver,
        sizeof(echoserver)) < 0) {
        perror("Failed to connect with server");
        exit(1);
    }

    dbgprt("open_remote: EXIT sock=%d\n",sock);

    return sock;
}

void *
terminal_thread(void *arg)
{
// NOTE/FIX: do this _once_
#if 1
    char *input_command = malloc(MAX_SIZE);
#endif

    tid = "term";

    char buffer[BUFFSIZE];
    int sock_ls = -1;

    while (1) {
        dbgprt("term: PROMPT\n");

        printf(">> ");
//memset(input_command,0,strlen(str));
// NOTE/BUG: this is a memory leak
#if 0
        char *input_command = malloc(MAX_SIZE);
#endif

        dbgprt("term: FGETS\n");
        fgets(input_command, MAX_SIZE, stdin);

// NOTE/BUG: code is broken to strip newline
#if 0
        if ((strlen(input_command) > 0) &&
            (input_command[strlen(input_command) - 1] == '\n'))
            input_command[strlen(input_command) - 1] = '\0';
#else
        input_command[strcspn(input_command,"\n")] = 0;
#endif

        dbgprt("term: COMMAND %s\n",dbgstr(input_command,-1));

        char list[] = "ls";
        char cp[] = "cp";

#if 0
        char s[100];
        printf("%s\n", getcwd(s,100));
        chdir("Desktop");
        printf("%s\n", getcwd(s,100));
#endif

        // exit program (and exit server)
        if (strcmp(input_command,"exit") == 0) {
            if (sock_ls >= 0) {
                dbgprt("term: SENDEXIT\n");
                if (send(sock_ls,"exit",4,0) < 0) {
                    perror("send/exit");
                    exit(1);
                }
                break;
            }
        }

        if (strcmp(input_command, list) == 0) {
            // ls code will run here

        }

        if ((input_command[0] == '.') && (input_command[1] == 'l')) {
            printf("remote ls\n");
            char ip[20];
            const char c[2] = " ";

            // strcpy(str,input_command);
            char *token;

            // get the first token
            token = strtok(input_command, c);

            // walk through other tokens
            int i = 0;

            while (token != NULL && i != -1) {
                token = strtok(NULL, c);
                i--;
            }

#if 1
            if (token == NULL) {
                token = "127.0.0.1";
                printf("no IP address found -- using %s\n",token);
            }
#endif

            if (sock_ls < 0)
                sock_ls = open_remote(token,9191);

            char s[100];

            strcpy(s, "ls");

// NOTE/BUG: this blows away the "s" in "ls" because s is _set_ with strcpy
#if 0
            s[strlen(s) - 1] = '\0';    // fgets doesn't automatically discard '\n'
#endif
            unsigned int echolen;
            echolen = strlen(s);

            int received = 0;

            /* send() from client; */
            if (send(sock_ls, s, echolen, 0) != echolen) {
                perror("Mismatch in number of sent bytes");
            }

            fprintf(stdout, "Message from server: ");

            int bytes = 0;

            /* recv() from server; */
            if ((bytes = recv(sock_ls, buffer, echolen, 0)) < 1) {
                perror("Failed to receive bytes from server");
            }
            received  = bytes;
            buffer[bytes] = '\0';
            /* Assure null terminated string */
            fprintf(stdout, buffer);

            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_ls, buffer, BUFFSIZE - 1, 0)) >= BUFFSIZE - 1);
            buffer[bytes] = '\0';
            printf("%s\n", buffer);
            printf("\n");

            continue;
        }
    }

    dbgprt("term: EXIT\n");

    return (void *) 0;
}

int
ls_loop(int new_socket)
{

    dbgprt("ls_loop: ENTER new_socket=%d\n",new_socket);

//code for ls

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

    int stop = 0;

    while (1) {
        memset(data, 0, MAX);
        // this will make server wait for another command to run until it
        // receives exit
        data[0] = '\0';

        if ((received = recv(new_socket, buffer, BUFFSIZE, 0)) < 0) {
            perror("Failed");
        }
        buffer[received] = '\0';

        strcpy(data, buffer);
        dbgprt("ls_loop: COMMAND %s\n",dbgstr(data,-1));

        // this will force the code to exit
#if 0
        if (strcmp(data, "exit") == 0)
            exit(0);
        puts(data);
#else
        if (strncmp(data, "exit", 4) == 0) {
            dbgprt("ls_loop: EXIT/COMMAND\n");
            stop = 1;
            break;
        }
#endif

        char *args[100];

        setup(data, args, 0);
        int pipefd[2], length;

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

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

        if (pid == 0) {
// NOTE/BUG: no need to close before dup2
#if 0
            close(1);                   // close the original stdout
#endif
            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
            exit(1);
        }

        if (pid < 0) {
            perror("fork");
            exit(1);
        }

        dbgprt("ls_loop: PARENT\n");
        close(pipefd[1]);

        while (length = read(pipefd[0], path, MAX - 1)) {
            dbgprt("ls_loop: DATAREAD %s\n",dbgstr(path,length));

            if (send(new_socket, path, length, 0) != length) {
                perror("Failed");
            }

            memset(path, 0, MAX);
        }

        close(pipefd[0]);
    }

    dbgprt("ls_loop: EXIT stop=%d\n",stop);
}

void *
server_socket_ls(void *arg)
{

    tid = "ls";

    dbgprt("lsmain: ENTER\n");

    do {
        server_arg *s = (server_arg *) arg;
        int server_fd, new_socket;
        struct sockaddr_in address;
        int addrlen = sizeof(address);

        dbgprt("lsmain: SOCKET\n");

        // Creating socket file descriptor
        if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
            perror("socket failed");
            exit(EXIT_FAILURE);
        }
        int enable = 1;

        if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &enable,
            sizeof(int)) < 0) {
            perror("error");
        }

        address.sin_family = AF_INET;
        address.sin_addr.s_addr = INADDR_ANY;
        address.sin_port = htons(s->portNum);

        dbgprt("lsmain: BIND prtNum=%u\n",s->portNum);
        if (bind(server_fd, (struct sockaddr *) &address, sizeof(address))
            < 0) {
            perror("bind failed");
        }

        dbgprt("lsmain: LISTEN\n");
        if (listen(server_fd, 3) < 0) {
            perror("listen");
        }

        while (1) {
            if ((new_socket = accept(server_fd, (struct sockaddr *) &address,
                (socklen_t *) & addrlen)) < 0) {
                perror("accept");
            }

            dbgprt("lsmain: ACCEPTED\n");

            int stop = ls_loop(new_socket);
            close(new_socket);

            if (stop) {
                dbgprt("lsmain: STOP\n");
                break;
            }
        }
    } while (0);

    dbgprt("lsmain: EXIT\n");

    return (void *) 0;
}

void *
server_socket_file(void *arg)
{

    tid = "file";

    dbgprt("file: ENTER\n");

    server_arg1 *s1 = (server_arg1 *) arg;
    int server_fd, new_socket;
    struct sockaddr_in address;
    int addrlen = sizeof(address);

    // Creating socket file descriptor
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
    int enable = 1;

    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int))
        < 0) {
        perror("error");
    }

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(s1->portNum);

    dbgprt("file: BIND portNum=%u\n",s1->portNum);

    if (bind(server_fd, (struct sockaddr *) &address, sizeof(address)) < 0) {
        perror("bind failed");

    }
    if (listen(server_fd, 3) < 0) {
        perror("listen");
    }

    if ((new_socket = accept(server_fd, (struct sockaddr *) &address,
        (socklen_t *) & addrlen)) < 0) {
        perror("accept");
    }

    printf("Server Connected\n");
}

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

    tid = "main";

    tsczero = tscgetf();

    server_arg *s = (server_arg *) malloc(sizeof(server_arg));
    server_arg1 *s1 = (server_arg1 *) malloc(sizeof(server_arg1));
    pthread_t id_1;
    pthread_t id_2;
    pthread_t id_3;

    xfdbg = fopen("debug.txt","w");
    setlinebuf(xfdbg);

    if (pthread_create(&id_3, NULL, terminal_thread, NULL) != 0) {
        perror("pthread_create");
    }

// NOTE/BUG: this port (or the one below) doesn't match the client code
// port of 5126
    s->portNum = 9191;
    pthread_create(&id_1, NULL, server_socket_ls, s);

    s1->portNum = 6123;
    if (0)
        pthread_create(&id_2, NULL, server_socket_file, s1);

    pthread_join(id_1, NULL);
    if (0)
        pthread_join(id_2, NULL);
    pthread_join(id_3, NULL);

// NOTE/BUG: pthread_exit in main thread is wrong
#if 0
    pthread_exit(0);
#else

    fclose(xfdbg);

    return 0;
#endif
}

這是除錯輸出:

[0.000170689/  ls] lsmain: ENTER
[0.000240819/  ls] lsmain: SOCKET
[0.000281554/  ls] lsmain: BIND prtNum=9191
[0.000207250/term] term: PROMPT
[0.000312276/term] term: FGETS
[0.000372488/  ls] lsmain: LISTEN
[2.367264029/term] term: COMMAND '.l'
[2.367295218/term] open_remote: ENTER ip='127.0.0.1' port=9191
[2.367346382/term] term: port=9191
[2.367434666/term] open_remote: EXIT sock=6
[2.367439573/  ls] lsmain: ACCEPTED
[2.367455805/  ls] ls_loop: ENTER new_socket=5
[2.367467511/  ls] ls_loop: COMMAND 'ls'
[2.367636543/  ls] ls_loop: PARENT
[2.369013467/  ls] ls_loop: DATAREAD 'debug.txt{0A}fix1{0A}fix1.c{0A}orig{0A}orig.c{0A}orig.txt{0A}out{0A}'
[2.369206789/term] term: PROMPT
[2.369222828/term] term: FGETS
[20.551357125/term] term: COMMAND 'exit'
[20.551378790/term] term: SENDEXIT
[20.551452423/term] term: EXIT
[20.551586028/  ls] ls_loop: COMMAND 'exit'
[20.551609143/  ls] ls_loop: EXIT/COMMAND
[20.551615857/  ls] ls_loop: EXIT stop=1
[20.551649125/  ls] lsmain: STOP
[20.551656969/  ls] lsmain: EXIT

轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/479879.html

標籤:C 插座 线程

上一篇:一個文本由套接字不停地發送,在一個回圈中,我希望它只發送一次

下一篇:并發服務器執行緒-給出系結錯誤

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • Git本地庫既關聯GitHub又關聯Gitee

    創建代碼倉庫 使用gitee舉例(github和gitee差不多) 1.在gitee右上角點擊+,選擇新建倉庫 ? 2.選擇填寫倉庫資訊,然后進行創建 ? 3.服務端已經準備好了,本地開始作準備 (1)Git 全域設定 git config --global user.name "成鈺" git c ......

    uj5u.com 2020-09-10 05:04:14 more
  • CODING DevOps 代碼質量實戰系列第二課,相約周三

    隨著 ToB(企業服務)的興起和 ToC(消費互聯網)產品進入成熟期,線上故障帶來的損失越來越大,代碼質量越來越重要,而「質量內建」正是 DevOps 核心理念之一。**《DevOps 代碼質量實戰(PHP 版)》**為 CODING DevOps 代碼質量實戰系列的第二課,同時也是本系列的 PHP ......

    uj5u.com 2020-09-10 05:07:43 more
  • 推薦Scrum書籍

    推薦Scrum書籍 直接上干貨,推薦書籍清單如下(推薦有順序的哦) Scrum指南 Scrum精髓 Scrum敏捷軟體開發 Scrum捷徑 硝煙中的Scrum和XP : 我們如何實施Scrum 敏捷軟體開發:Scrum實戰指南 Scrum要素 大規模Scrum:大規模敏捷組織的設計 用戶故事地圖 用 ......

    uj5u.com 2020-09-10 05:07:45 more
  • CODING DevOps 代碼質量實戰系列最后一課,周四發車

    隨著 ToB(企業服務)的興起和 ToC(消費互聯網)產品進入成熟期,線上故障帶來的損失越來越大,代碼質量越來越重要,而「質量內建」正是 DevOps 核心理念之一。 **《DevOps 代碼質量實戰(Java 版)》**為 CODING DevOps 代碼質量實戰系列的最后一課,同時也是本系列的 ......

    uj5u.com 2020-09-10 05:07:52 more
  • 敏捷軟體工程實踐書籍

    Scrum轉型想要做好,第一步先了解并真正落實Scrum,那么我推薦的Scrum書籍是要看懂并實踐的。第二步是團隊的工程實踐要做扎實。 下面推薦工程實踐書單: 重構:改善既有代碼的設計 決議極限編程 : 擁抱變化 代碼整潔代碼 程式員的職業素養 修改代碼的藝術 撰寫可讀代碼的藝術 測驗驅動開發 : ......

    uj5u.com 2020-09-10 05:07:55 more
  • Jenkins+svn+nginx實作windows環境自動部署vue前端專案

    前面文章介紹了Jenkins+svn+tomcat實作自動化部署,現在終于有空抽時間出來寫下Jenkins+svn+nginx實作自動部署vue前端專案。 jenkins的安裝和配置已經在前面文章進行介紹,下面介紹實作vue前端專案需要進行的哪些額外的步驟。 注意:在安裝jenkins和nginx的 ......

    uj5u.com 2020-09-10 05:08:49 more
  • CODING DevOps 微服務專案實戰系列第一課,明天等你

    CODING DevOps 微服務專案實戰系列第一課**《DevOps 微服務專案實戰:DevOps 初體驗》**將由 CODING DevOps 開發工程師 王寬老師 向大家介紹 DevOps 的基本理念,并探討為什么現代開發活動需要 DevOps,同時將以 eShopOnContainers 項 ......

    uj5u.com 2020-09-10 05:09:14 more
  • CODING DevOps 微服務專案實戰系列第二課來啦!

    近年來,工程專案的結構越來越復雜,需要接入合適的持續集成流水線形式,才能滿足更多變的需求,那么如何優雅地使用 CI 能力提升生產效率呢?CODING DevOps 微服務專案實戰系列第二課 《DevOps 微服務專案實戰:CI 進階用法》 將由 CODING DevOps 全堆疊工程師 何晨哲老師 向 ......

    uj5u.com 2020-09-10 05:09:33 more
  • CODING DevOps 微服務專案實戰系列最后一課,周四開講!

    隨著軟體工程越來越復雜化,如何在 Kubernetes 集群進行灰度發布成為了生產部署的”必修課“,而如何實作安全可控、自動化的灰度發布也成為了持續部署重點關注的問題。CODING DevOps 微服務專案實戰系列最后一課:**《DevOps 微服務專案實戰:基于 Nginx-ingress 的自動 ......

    uj5u.com 2020-09-10 05:10:00 more
  • CODING 儀表盤功能正式推出,實作作業資料可視化!

    CODING 儀表盤功能現已正式推出!該功能旨在用一張張統計卡片的形式,統計并展示使用 CODING 中所產生的資料。這意味著無需額外的設定,就可以收集歸納寶貴的作業資料并予之量化分析。這些海量的資料皆會以圖表或串列的方式躍然紙上,方便團隊成員隨時查看各專案的進度、狀態和指標,云端協作迎來真正意義上 ......

    uj5u.com 2020-09-10 05:11:01 more
最新发布
  • windows系統git使用ssh方式和gitee/github進行同步

    使用git來clone專案有兩種方式:HTTPS和SSH:
    HTTPS:不管是誰,拿到url隨便clone,但是在push的時候需要驗證用戶名和密碼;
    SSH:clone的專案你必須是擁有者或者管理員,而且需要在clone前添加SSH Key。SSH 在push的時候,是不需要輸入用戶名的,如果配置... ......

    uj5u.com 2023-04-19 08:41:12 more
  • windows系統git使用ssh方式和gitee/github進行同步

    使用git來clone專案有兩種方式:HTTPS和SSH:
    HTTPS:不管是誰,拿到url隨便clone,但是在push的時候需要驗證用戶名和密碼;
    SSH:clone的專案你必須是擁有者或者管理員,而且需要在clone前添加SSH Key。SSH 在push的時候,是不需要輸入用戶名的,如果配置... ......

    uj5u.com 2023-04-19 08:35:34 more
  • 2023年農牧行業6大CRM系統、5大場景盤點

    在物聯網、大資料、云計算、人工智能、自動化技術等現代資訊技術蓬勃發展與逐步成熟的背景下,數字化正成為農牧行業供給側結構性變革與高質量發展的核心驅動因素。因此,改造和提升傳統農牧業、開拓創新現代智慧農牧業,加快推進農牧業的現代化、資訊化、數字化建設已成為農牧業發展的重要方向。 當下,企業數字化轉型已經 ......

    uj5u.com 2023-04-18 08:05:44 more
  • 2023年農牧行業6大CRM系統、5大場景盤點

    在物聯網、大資料、云計算、人工智能、自動化技術等現代資訊技術蓬勃發展與逐步成熟的背景下,數字化正成為農牧行業供給側結構性變革與高質量發展的核心驅動因素。因此,改造和提升傳統農牧業、開拓創新現代智慧農牧業,加快推進農牧業的現代化、資訊化、數字化建設已成為農牧業發展的重要方向。 當下,企業數字化轉型已經 ......

    uj5u.com 2023-04-18 08:00:18 more
  • 計算機組成原理—存盤器

    計算機組成原理—硬體結構 二、存盤器 1.概述 存盤器是計算機系統中的記憶設備,用來存放程式和資料 1.1存盤器的層次結構 快取-主存層次主要解決CPU和主存速度不匹配的問題,速度接近快取 主存-輔存層次主要解決存盤系統的容量問題,容量接近與價位接近于主存 2.主存盤器 2.1概述 主存與CPU的聯 ......

    uj5u.com 2023-04-17 08:20:31 more
  • 談一談我對協同開發的一些認識

    如今各互聯網公司普通都使用敏捷開發,采用小步快跑的形式來進行專案開發。如果是小專案或者小需求,那一個開發可能就搞定了。但對于電商等復雜的系統,其功能多,結構復雜,一個人肯定是搞不定的,所以都是很多人來共同開發維護。以我曾經待過的商城團隊為例,光是后端開發就有七十多人。 為了更好地開發這類大型系統,往 ......

    uj5u.com 2023-04-17 08:18:55 more
  • 專案管理PRINCE2核心知識點整理

    PRINCE2,即 PRoject IN Controlled Environment(受控環境中的專案)是一種結構化的專案管理方法論,由英國政府內閣商務部(OGC)推出,是英國專案管理標準。
    PRINCE2 作為一種開放的方法論,是一套結構化的專案管理流程,描述了如何以一種邏輯性的、有組織的方法,... ......

    uj5u.com 2023-04-17 08:18:51 more
  • 談一談我對協同開發的一些認識

    如今各互聯網公司普通都使用敏捷開發,采用小步快跑的形式來進行專案開發。如果是小專案或者小需求,那一個開發可能就搞定了。但對于電商等復雜的系統,其功能多,結構復雜,一個人肯定是搞不定的,所以都是很多人來共同開發維護。以我曾經待過的商城團隊為例,光是后端開發就有七十多人。 為了更好地開發這類大型系統,往 ......

    uj5u.com 2023-04-17 08:18:00 more
  • 專案管理PRINCE2核心知識點整理

    PRINCE2,即 PRoject IN Controlled Environment(受控環境中的專案)是一種結構化的專案管理方法論,由英國政府內閣商務部(OGC)推出,是英國專案管理標準。
    PRINCE2 作為一種開放的方法論,是一套結構化的專案管理流程,描述了如何以一種邏輯性的、有組織的方法,... ......

    uj5u.com 2023-04-17 08:17:55 more
  • 計算機組成原理—存盤器

    計算機組成原理—硬體結構 二、存盤器 1.概述 存盤器是計算機系統中的記憶設備,用來存放程式和資料 1.1存盤器的層次結構 快取-主存層次主要解決CPU和主存速度不匹配的問題,速度接近快取 主存-輔存層次主要解決存盤系統的容量問題,容量接近與價位接近于主存 2.主存盤器 2.1概述 主存與CPU的聯 ......

    uj5u.com 2023-04-17 08:12:06 more