0

次のループは、プログラムのメイン内にあります。着信接続を受け入れ、スレッドがそれを処理します。

問題は、スレッドが終了するとすぐに、プログラム全体が終了することです。コードは次のとおりです。

#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#define BUFLEN 1500
#define MAXCON 30

char *returnTimeDate(int inputchoice);
void readWriteToClient(int inputconnfd);

int main(){

    int backlog = 10;

    int fd;
    fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd == -1) {
        // Error: unable to create socket
    }

    struct sockaddr_in cliaddr;
    socklen_t cliaddrlen = sizeof(cliaddr);

    struct sockaddr_in addr;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(5001);

    if (bind(fd, (struct sockaddr *) &addr, (socklen_t) sizeof(addr)) == -1) {
        fprintf(stderr,"Bind Didn't Work\n");
    }

    if (listen(fd, backlog) == -1) {
        fprintf(stderr,"Listen Didn't Work\n");
    }

    pthread_t *threadsArray = (pthread_t *)calloc(MAXCON, sizeof(pthread_t));
    pthread_t *threadPtr = threadsArray;

    int k;
    for(k = 0; k < MAXCON; k++){
        fprintf(stderr,"Make %d\n",k);
        int connfd;
        connfd = accept(fd, (struct sockaddr *) &cliaddr, &cliaddrlen);
        if (connfd == -1) {
            fprintf(stderr,"Accept Didn't Work\n");
        }
        fprintf(stderr,"Waited\n",k);
        pthread_create( &threadPtr, NULL, readWriteToClient, (void *)connfd);
        threadPtr++;
    }

    pthread_t *threadPtrJoin = threadsArray;

    for(k = 0; k < MAXCON; k++){
        fprintf(stderr,"Join %d\n",k);
        pthread_join( *threadPtrJoin, NULL);
        threadPtrJoin++;
    }

/*  readWriteToClient(connfd);*/

    close(fd);

    return 0;

}

void readWriteToClient(int inputconnfd){

    int connfd = inputconnfd;

    while(1){

        char *dateString = "DATE\r\n";
        char *timeString = "TIME\r\n";
        char *endString = "end";

        char *bufferTime = returnTimeDate(0);
        char *bufferDate = returnTimeDate(1);

        ssize_t i;
        ssize_t rcount;
        char buf[BUFLEN];
        char *toReturn = (char *)malloc(BUFLEN*sizeof(char));
        rcount = read(connfd, buf, BUFLEN);
        if((strcmp (buf, dateString)) == 0){
            strcpy(toReturn, bufferDate);
        }
        if((strcmp (buf, timeString)) == 0){
            strcpy(toReturn, bufferTime);
        }
        if((strcmp (buf, endString)) == 0){
            goto outside;
        }
        if (rcount == -1) {
            // Error has occurred
            printf("Error: rcount -1");
        }

/*      fprintf(stderr,"I have received = %s\n",buf);*/

        if (write(connfd, toReturn, BUFLEN) == -1) {
            fprintf(stderr,"I didn't write = %s\n",buf);    
        }
    }

    outside: return;

}

char *returnTimeDate(int inputchoice){

    time_t timer;
    char *bufferTimee = (char *)malloc(25*sizeof(char));
    char *bufferDatee = (char *)malloc(25*sizeof(char));
    struct tm* tm_info;
    time(&timer);
    tm_info = localtime(&timer);
    strftime(bufferTimee, 25, "%H:%M:%S\n\0", tm_info);
    strftime(bufferDatee, 25, "%d:%m:%Y\n\0", tm_info);

    if(inputchoice == 0){
        return bufferTimee;
    }else{
        return bufferDatee;
    }

}

なぜこれをしているのですか?

4

2 に答える 2

4

pthread の使用法には、非常に間違っている点がいくつかあります。

まず第一に、あなたはこれを意味したと思います:

int st = pthread_create(&threadPtr[k], NULL, readWriteToClient, (void *)connfd);
if (st != 0) {
    /* handle error */
}

次の点に注意してください。

  • pthread_create()inの戻り値を格納し、stそのエラー ケースを処理しています。
  • ( type の) ではなく、( &threadPtr[k]type の)を渡します。これが問題の原因である可能性があります。pthread_t *&threadPtrpthread_t **

しかし、あなたのコードで私が抱えている主な問題の 1 つは、に渡すreadWriteToClientことによって未定義の動作を呼び出していることですpthread_create()。プロトタイプは次のpthread_createとおりです。

int pthread_create(pthread_t *restrict,
                   const pthread_attr_t *restrict,
                   void *(*start_routine)(void*), 
                   void *restrict arg);

に変更&threadPtrしても&threadPtr[k]、次のように呼び出します。

int pthread_create(pthread_t *restrict,
                   const pthread_attr_t *restrict,
                   void (*start_routine)(int),      // oops!
                   void *restrict arg);

したがって、はpthread_create()あるタイプの関数へのポインターを受け入れますが、別のタイプの関数へのポインターを渡しています (C11、6.7.6.3/15、強調鉱山):

2 つの関数型に互換性を持たせるには、両方で互換性のある戻り値の型を指定する必要があります。さらに、両方が存在する場合、パラメータ型リストは、パラメータの数と省略記号ターミネータの使用において一致する必要があります。対応するパラメータは、互換性のある型を持つ必要があります。[...]

関数へのポインターは暗黙的に変換され、とにかく関数が呼び出されますが、標準 (C11、6.3.2.3/8、強調鉱山) に従って、これは違法です。

あるタイプの関数へのポインターは、別のタイプの関数へのポインターに変換され、再び元に戻される場合があります。結果は元のポインターと等しくなります。変換されたポインターを使用して、参照される型と互換性のない型を持つ関数を呼び出す場合、動作は undefinedです。

未定義の動作を呼び出しているため、実行後にコードがどのように動作するかはわかりません。

また、inta から a への変換void *とその逆の変換は、情報の損失なしに行われるとは限らないことに注意してください (これは実装定義です) ので、注意してください。

コードには、警告を有効にしてコンパイルした場合に表示されるエラーが他にもいくつかあります。これは常に行う必要があります。

于 2013-01-23T19:23:13.557 に答える
-1

あなたのコンパイラは、互換性のないポインター型について警告を発していたに違いありません....

私の提案は、コンパイル段階ですべての警告を修正することです。

これが行われた場合、pthread 関数のパラメーターは int ではなく void へのポインターでなければならないことに気付くでしょう。

さらに、後者の関数は、スタックに大きな混乱を引き起こす可能性のある void だけでなく、void へのポインターを返さなければなりません。

まず、接続 fds の配列を使用します

int connfd[MAXCON];

次に、connfdを保存します

connfd[k] = accept(fd, (struct sockaddr *) &cliaddr, &cliaddrlen);

その後、変更

pthread_create( threadPtr, NULL, readWriteToClient, connfd);

pthread_create( threadPtr, NULL, readWriteToClient, (void *) &connfd[k]);

変更する

void readWriteToClient(int inputconnfd)

void *readWriteToClient(void *inputconnfd)

次に、それをローカル変数に割り当てます

int connfd = *((int *) inputconnfd);

それが機能するかどうか教えてください

于 2013-01-23T18:43:04.030 に答える