Java客户端和C++;服务器,有时接收整个信息 我用TCP编写了多线程C++服务器和java客户端。对于短字符串,它可以正常工作,但是当我想要发送大字符串(例如40个字符)时,服务器只接收其中的几个字符串,而客户端正在等待响应
多线程部分工作正常 这是密码。(对于变量的注释和名称,我很抱歉。我是西班牙人。) 服务器C++Java客户端和C++;服务器,有时接收整个信息 我用TCP编写了多线程C++服务器和java客户端。对于短字符串,它可以正常工作,但是当我想要发送大字符串(例如40个字符)时,服务器只接收其中的几个字符串,而客户端正在等待响应,java,c++,client-server,Java,C++,Client Server,多线程部分工作正常 这是密码。(对于变量的注释和名称,我很抱歉。我是西班牙人。) 服务器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 so
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;
}
您不应该直接在套接字服务器(和客户端)中调用read(),而应该使用select()来知道套接字何时可以读取或写入。只调用read/write而不调用select()被认为是不好的做法。select()将一直阻止,直到套接字准备好读/写,或者直到超时(如果您配置了超时)
这里有一个很好的例子,他们使用select():TCP是一种面向流的传输-对写入和读取的调用之间的对应关系不是1:1(就像UDP这样面向数据报的传输)
在收到一条(或多条)完整的消息之前,您需要在一个循环中不断阅读。这取决于您如何编码以确定消息的结尾。您应该不惜一切代价避免使用goto!在适合应用程序的情况下,可以使用阻止读/写调用吗?它可能无法像反应堆那样扩展到多个插座,但并不是所有需要的东西。@没用,可能还可以,但不可取。如果他正在学习套接字等,为什么不正确开始呢?我添加了select(),但问题出在客户端,我不知道为什么,但是,当我使用readLine并介绍zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz。您也可以尝试发布客户代码(在这里或在另一个问题中),我们可以查看(请告诉我何时发布,我会尽力提供帮助)。马上去马德里。谢谢你的帮助!如果我还有另一个问题,我会在这里问。描述TCP为面向流的词汇选择不当。UDP通常用于流式音频/视频。但你是对的,他需要确保他读取了所有的数据。Select()有助于了解更多数据:)尽管如此:它有类型SOCK\u STREAM
,行为有点像iostream
(因为它们都是双向的,并且面向字节或字符)。此命名方案先于有损多媒体流的数据报传输的流行使用。