web-dev-qa-db-ja.com

Unixのソケットを使用したCでのファイル(サーバー/クライアント)の送受信

何よりもまず、これを読んで助けてくれてありがとう、私はとても感謝しています。
2番目に申し訳ありませんが、私はまだこのサイトに不慣れであり、英語は私の母国語ではないため、フォーマットや言語の間違いをする可能性があります。あらかじめお詫び申し上げます。
また、私のCの知識はそれほど良くありませんが、学び、向上させたいと思っています。
さて、当面の問題について:

私がする必要があるのは、クライアントとサーバーを作成し、サーバーに着信接続をリッスンさせることです。
次に、クライアントに非常に大きなテキストファイル(1つのファイルのみになることはわかっています)をサーバーに送信させます。
サーバーはファイルに対して何らかの操作を実行します(送信されたファイルに対してスクリプトを実行し、「output.txt」という出力で別のファイルを生成します)。次に、サーバーはoutput.txtファイルをクライアントに送り返す必要があります。

今、私はクライアントとサーバーを作る方法をちょっと手に入れました(私はこのサイトでbeejガイドと他のいくつかのものを読みました)、おそらく私はいくつかの間違いをしました。サーバーがファイルを受信し、スクリプトを呼び出して、他のファイルをクライアントに送り返すのに助けが必要です。今のところ私がしたのはサーバーとクライアントです...どうすればいいのかよくわかりません。
ちなみに、私はこのサイトとインターネットで見つけたものを使用してこのファイルを作成しました。私はプログラマーがあまり得意ではないので、あまり乱雑にならないことを願っています。

これはclient.cです

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


#define SOCKET_PORT "50000"
#define SOCKET_ADR "localhost"
#define filename "/home/aryan/Desktop/input.txt"


void error(const char *msg)
{
    perror(msg);
    exit(0);
}


int main()
{
/* Making the client */
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;

char buffer[256];

portno = atoi(SOCKET_PORT);

sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) 
    error("ERROR opening socket");

server = gethostbyname(SOCKET_ADR);

if (server == NULL) 
{
    fprintf(stderr,"ERROR, no such Host\n");
    exit(0);
}

bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr, 
     (char *)&serv_addr.sin_addr.s_addr,
     server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
    error("ERROR connecting");

/* Time to send the file */
FILE *pf;
unsigned long fsize;

pf = fopen(filename, "rb");
if (pf == NULL) 
{
    printf("File not found!\n");
    return 1;
}
else 
{
    printf("Found file %s\n", filename);

    fseek(pf, 0, SEEK_END);
    fsize = ftell(pf);
    rewind(pf);

    printf("File contains %ld bytes!\n", fsize);
    printf("Sending the file now");
}

while (1) 
{
    // Read data into buffer.  We may not have enough to fill up buffer, so we
    // store how many bytes were actually read in bytes_read.
    int bytes_read = fread(buffer, sizeof(char),sizeof(buffer), pf);
    if (bytes_read == 0) // We're done reading from the file
        break;

    if (bytes_read < 0) 
    {
        error("ERROR reading from file"); 
    }

    // You need a loop for the write, because not all of the data may be written
    // in one call; write will return how many bytes were written. p keeps
    // track of where in the buffer we are, while we decrement bytes_read
    // to keep track of how many bytes are left to write.
    void *p = buffer;
    while (bytes_read > 0) 
    {
        int bytes_written = write(sockfd, buffer, bytes_read);
        if (bytes_written <= 0) 
        {
            error("ERROR writing to socket\n");
        }
        bytes_read -= bytes_written;
        p += bytes_written;
    }
}       

printf("Done Sending the File!\n");
printf("Now Closing Connection.\n");

fclose(pf);
close(sockfd);
return 0;
}

これはserver.cです:

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

#define SOCKET_PORT 50000
#define filename "/home/aryan/Desktop/output.txt"


void error(const char *msg)
{
    perror(msg);
    exit(1);
}

void* client_thread_proc(void* arg)
{
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
FILE *fp;

int thisfd = (int)arg;
printf("Server %d: accepted = %d\n", getpid(), thisfd);

if (thisfd < 0) 
{ 
    printf("Accept error on server\n");
    error("ERROR on accept"); 
    return NULL;
}

printf("Connection %d accepted\n", thisfd);

fp = fopen(filename, "a+b");
if (fp == NULL) 
{
    printf("File not found!\n");
    return NULL;
}
else 
{
    printf("Found file %s\n", filename);
}

/* Time to Receive the File */
while (1)
{
    bzero(buffer,256);
    n = read(thisfd,buffer,255);
    if (n < 0) error("ERROR reading from socket");

    n = fwrite(buffer, sizeof(char), sizeof(buffer), fp);
    if (n < 0) error("ERROR writing in file");

    n = write(thisfd,"I am getting your file...",25);
    if (n < 0) error("ERROR writing to socket");
} /* end child while loop */

fclose(fp);

return NULL;
}

void serve_it(int Client)
{
    void* arg = (void*)Client;
    pthread_t new_thread;
    pthread_create( &new_thread, NULL, &client_thread_proc, arg);
}

/* Making Server */
int main()
{
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
FILE *fp;

signal (SIGCHLD, SIG_IGN);

sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) 
    error("ERROR opening socket");

bzero((char *) &serv_addr, sizeof(serv_addr));

serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(SOCKET_PORT);

if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 
      error("ERROR on binding");

listen(sockfd,5);

clilen = sizeof(cli_addr);

while (1)
{
    printf("Server %d accepting connections\n", getpid());

    newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);

    serve_it(newsockfd);
}  // serving loop


close(sockfd);   
return 0; 
}

先に進む方法についていくつかの指針が欲しいのですが...
クライアントからサーバーに受け取ったファイルにスクリプトを実行するにはどうすればよいですか?
新しいファイルを同じクライアントに送り返すにはどうすればよいですか?
そして、コードのエラーについて私を助けてくれたら、ありがたいです。

長い間お読みいただき、誠にありがとうございました。ごきげんよう!

6
AscaL

最初のエラー:

#define filename = "Home\\Desktop\\input.txt"

する必要があります

#define filename "Home\\Desktop\\input.txt"

それ以外の場合、プリプロセッサは

= "Home\Desktop\input.txt"

ではありません

"Home\\Desktop\\input.txt"

あなたが期待すること。

2番目のエラー:

int bytes_read = read(filename /* THAT IS WRONG, FILE HANDLE MUST BE HERE */, buffer, strlen(buffer) /* also WRONG, must be MAX_BYTES_IN_BUFFER or something */ );

ここでは、「pf」(fopen()呼び出しで開いた)から読み取る必要があり、最後の引数は読み取りたいバイト数である必要があります。したがって、strlen(buffer)を実行し、プログラムのランタイムの開始時にバッファーにガベージが含まれていると、クラッシュが発生します。 strlen()は、有効なゼロで終了する文字列に対してのみ呼び出す必要があります。配列のサイズではありません。

編集:精巧なサーバーのループ:

while (1)
{
    printf("Server %d accepting connections\n", getpid());

    newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);

    serve_it(newsockfd);
}  // serving loop

Serve_it():

void serve_int(int Client)
{
    void* arg = (void*)Client;
    pthread_t new_thread;
    pthread_create( new_thread, NULL, &client_thread_proc, arg);
}

void* client_thread(void* arg)
{
    int thisfd = (int)arg;
    printf("Server %d: accepted = %d\n", getpid(), thisfd);

    if (thisfd < 0) 
    { 
        printf("Accept error on server\n");
        error("ERROR on accept"); 
        return NULL;
    }

    printf("Connection %d accepted\n", thisfd);

    fp = fopen(filename, "a+b");
    if (fp == NULL) 
    {
        printf("File not found!\n");
        return NULL;
    }
    else 
    {
        printf("Found file %s\n", filename);
    }

    /* Time to Receive the File */
    while (1)
    {
        bzero(buffer,256);
        n = read(thisfd,buffer,255);
        if (n < 0) error("ERROR reading from socket");

        n = fwrite(buffer, sizeof(buffer), 1, fp);
        if (n < 0) error("ERROR writing in file");

        n = write(thisfd,"I am getting your file...",25);
        if (n < 0) error("ERROR writing to socket");
    } /* end child while loop */

    return NULL;
}
5
Viktor Latypov