-3

サーバー側で実行するソケットプログラミングのコードを書いています。現在、クライアントは基本的にデータを文字列の形式で(TCP経由で)送信します。私のサーバーコードがしようとしているのは、文字列を読み取り、配列に数値のみを格納して、取得したこれらの数値に対して他の機能を実行できるようにすることです。しかし、私はこの機能を実装する方法を正確に知りません。

/* tcpserver.c */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>


int main()
{
    int sock, connected, bytes_recieved , true = 1;  
    int n[3],i,arr[3][5];
    char send_data [1024] , recv_data[1024];       

    struct sockaddr_in server_addr,client_addr;    
    int sin_size;

    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("Socket");
        exit(1);
    }

    if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int)) == -1) {
        perror("Setsockopt");
        exit(1);
    }

    server_addr.sin_family = AF_INET;         
    server_addr.sin_port = htons(5001);     
    server_addr.sin_addr.s_addr = INADDR_ANY; 
    bzero(&(server_addr.sin_zero),8); 

    if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
        perror("Unable to bind");
        exit(1);
    }

    if (listen(sock, 5) == -1) {
        perror("Listen");
        exit(1);
    }

    printf("\nTCPServer Waiting for client on port 5000");
    fflush(stdout);

    while(1) {  
        sin_size = sizeof(struct sockaddr_in);
        connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size);
        printf("\n I got a connection from (%s , %d)",
               inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
        while (1) {
            printf("\n SEND (q or Q to quit) : ");
            gets(send_data);

            if (strcmp(send_data , "q") == 0 || strcmp(send_data , "Q") == 0) {
                send(connected, send_data,strlen(send_data), 0); 
                close(connected);
                break;
            } 
            else {
                send(connected, send_data,strlen(send_data), 0);
            } 

            for(i=0;i<3;i++) {
                bytes_recieved= recv(connected,recv_data,1024,0);
                recv_data[bytes_recieved] = '\0';

                n[i]=atoi(recv_data);     
            }

            if (strcmp(recv_data , "q") == 0 || strcmp(recv_data , "Q") == 0) {
                close(connected);
                break;
            }
            else  {
                for(i=0;i<3;i++) {
                    printf("\n RECIEVED DATA = %d \n",n[i]);
                    fflush(stdout);
                }
            }
        } /* end inner while */

        close(sock);
        return 0;
    } /* end outer while */
} /* end main */
4

1 に答える 1

1

あなたは実際に問題が何であるかを言わなかったし、あなたのクライアントコードを見せなかった。しかし、これはサーバーループの問題だと思います。

for(i=0;i<3;i++)
{
    bytes_recieved= recv(connected,recv_data,1024,0);
    recv_data[bytes_recieved] = '\0';
    n[i]=atoi(recv_data);     
}

まず、recv()が1024を返す場合、recv_data[1024]に「\0」を書き込むことになります。この配列の有効なインデックス範囲は0..1023です。この関数の先頭でrecv_dataを1024ではなく1025バイトの長さに宣言することで、これを簡単に修正できます。

しかし、実際の問題は、クライアントが実際に送信したバイト数に関係なく、recv()が期待される長さを返すことを期待できないことです。(または他の人が言うように:「TCPはSTREAMプロトコルです」)

これは、recv()ループに必要なものである可能性があります。

for (i = 0; i < 3; i++)
{
    j=0; // j is declared as 32-bit int above
    success = ReadIntegerFromSocketStream(connected, &j);
    if (success == 0)
    {
        close(connected);
        connected = -1;
        break;
    }
    n[i] = j;
}

int ReadIntegerFromSocketStream(int sock, int* result)
{
    int ret;
    int count= 0;

    char COMPILE_TIME_ASSERT[ (sizeof(int)==4) ? 1 : -1 ];

    unsigned char data[4];

    while (bytes_received < 4)
    {
        ret = recv(sock, data+count, 4-count, 0);
        if (ret <= 0)
        {
            /* socket got closed, abort */
            return 0;
        }
        count += ret;
    }

    memcpy(&result, data, 4);

    // not shown: calling result = ntohl(result);
    // I'll let you look this function up

    return 1;
}
于 2012-11-11T07:48:20.150 に答える