1

TCPを使用してマルチスレッドC++サーバーとJavaクライアントを作成しています。短い文字列では問題なく動作しますが、大きな文字列(40文字など)を送信したい場合、サーバーはそのうちのいくつかしか受信せず、クライアントは応答を待機しています。

マルチスレッド部分は正常に機能します。

ここにコードがあります。(変数のコメントと名前でごめんなさい。私はスペイン語です。)

サーバーC++

void* SocketHandler(void*);


int main(int argv, char** argc){



//Puerto en el que recibe
int host_port= 1101;

//Estructura usada para especificar una direccion local o remota a la que conectar un socket
struct sockaddr_in my_addr;

int hsock;
int * p_int ;
int errno;

socklen_t addr_size = 0;
int* csock;
sockaddr_in sadr;
pthread_t thread_id=0;

//Se inicializa socket
hsock = socket(AF_INET, SOCK_STREAM, 0);
//Para comprobar que el socket se ha inicializado correctamente
if(hsock == -1){
    printf("Error inicializando socket %d\n", errno);
    goto FINISH;
}

//Se reserva memoria
p_int = (int*)malloc(sizeof(int));
*p_int = 1;

//Se comprueba que al introducir las opciones del socket se introduzcan correctamente   
if( (setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1 )||
    (setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1 ) ){
    printf("Error introduciendo opciones del socket %d\n", errno);
    //Se libera la memoria reservada
    free(p_int);
    goto FINISH;
}
//Se libera la memoria reservada
free(p_int);

//Se añade la familia de direcciones a la que pertenece IPV4
my_addr.sin_family = AF_INET ;
//Se añade el puerto que es
my_addr.sin_port = htons(host_port);

//Relleno de sin zero con 8 ceros
bzero((char *) &(my_addr.sin_zero), sizeof(my_addr.sin_zero));
//memset(&(my_addr.sin_zero), 0, 8);

//Se añade la dirección IP
my_addr.sin_addr.s_addr = INADDR_ANY ;

//Enlaza el socket con la dirección IP, puerto
if( bind( hsock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == -1 ){
    fprintf(stderr,"Error enlazando el socket, asegurate de que no hay nada más escuchando en este puerto %d\n",errno);
    goto FINISH;
}
//Se pone a escuchar
if(listen( hsock, 5) == -1 ){
    fprintf(stderr, "Error listening %d\n",errno);
    goto FINISH;
}


//Ahora se pasa a hacer las cosas en el servidor


addr_size = sizeof(sockaddr_in);

while(true){
    printf("Esperando a una conexión\n");
    //Se reserva memoria 
    csock = (int*)malloc(sizeof(long double));
    //Hay que encontrar porque no manda mas de x caracteres


    //LLamada que se bloquea esperando una conexion de un cliente
    if((*csock = accept( hsock, (struct sockaddr*)&sadr, &addr_size))!= -1){
        printf("---------------------\nRecibida conexión de %s\n",inet_ntoa(sadr.sin_addr));
        //Se crea un nuevo hilo por cliente, se llama a socket handler
        pthread_create(&thread_id,0,&SocketHandler, (void*)csock );
        //El almacenamiento del hilo puede ser reclamado cuando el hilo haya terminado
        pthread_detach(thread_id);
    }
    else{
        fprintf(stderr, "Error aceptando cliente %d\n", errno);
    }
}

FINISH:
;
}

void* SocketHandler(void* lp){
int *csock = (int*)lp;

//Buffer en donde se guarda lo recibido
char buffer[8192];
//Longitud del buffer
//int buffer_len = 8192;
//Contador para saber el número de caracteres del buffer
int bytecount;

//Relleno del buffer con ceros
bzero((char *) &buffer, sizeof(buffer));
//memset(buffer, 0, sizeof(buffer));
//Se recibe la informacion del socket y se comprueba que sea valida

//recv(buffer,offset,size,socketflags) 
//buffer es un array de bytes que es la localización en donde se van a guardar los datos
//offset es la posicion en el buffer de datos desde la cual se quiere empezar a guardar
//size es el número de bytes a recibir
//socketflags es la combinacion de flas que se quieren utilizar 0 significa ninguno 
/*if((bytecount = recv(*csock, buffer, sizeof(buffer), 0))== -1){
    fprintf(stderr, "Error recibiendo los datos %d\n", errno);
    goto FINISH;
}*/


if((bytecount = read(*csock,buffer,sizeof(buffer)))== -1){
        fprintf(stderr, "Error recibiendo los datos %d\n", errno);
    goto FINISH;
}

printf("Bytes recibidos %d\nstring recibido %s\n", bytecount, buffer);
//Copia el string al buffer
//strcat(buffer, " SERVER ECHO");




//Se tienen que poner parentesis por el uso de go to de arriba
{       


    string comando = buffer;


    if(comando.compare("zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz") == 0){

        strcpy(buffer,"yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy");


    }

}


//Envía el mensaje de vuelta con el string añadido

//send(buffer,offset,size,socketflags) 
//buffer es un array de bytes que contiene los datos a ser enviados
//offset es la posicion en el buffer de datos desde la cual se quiere empezar a enviar datos
//size es el número de bytes a enviar
//socketflags es la combinacion de flas que se quieren utilizar 0 significa ninguno

{
    //Se hace esto ya que en el cliente parece que si no le llegua salto de linea no continua, y se queda esperando
string bufferbarran =  buffer;
bufferbarran +="\n";    
strcpy(buffer,bufferbarran.c_str());
/*
if((bytecount = send(*csock, buffer, strlen(buffer), 0))== -1){
    fprintf(stderr, "Error enviando los datos %d\n", errno);
    goto FINISH;
}
*/
if((bytecount = write(*csock,buffer,strlen(buffer)))== -1){
        fprintf(stderr, "Error enviando los datos %d\n", errno);
    goto FINISH;
}
}

printf("Bytes enviados %d\n", bytecount);


FINISH:
//Se libera la memoria reservada

free(csock);

return 0;
}
4

2 に答える 2

1

ソケットサーバー(およびクライアント)で直接read()を呼び出す代わりに、select()を使用して、ソケットの読み取りまたは書き込みの準備ができたことを確認する必要があります。select()を呼び出さずに単に読み取り/書き込みを呼び出すことは悪い習慣と考えられています。select()は、ソケットの読み取り/書き込みの準備ができるまで、またはタイムアウトを構成した場合はタイムアウトになるまでブロックします。

select()を使用する良い例を次に示します。c++ソケットの選択と受信の問題

于 2012-05-29T13:20:12.310 に答える
1

TCPはストリーム指向のトランスポートです-呼び出し間の対応は1:1writereadはありません(UDPのようなデータグラム指向のトランスポートの場合のように)。

1つ(または複数)のメッセージ全体を受信するまで、ループで読み続ける必要があります。メッセージがどこで終わるかを理解するための何らかの方法をエンコードするのはあなた次第です。

于 2012-05-29T13:43:20.190 に答える