错误的通信c服务器和java客户端

问题描述:

我试图做一个tcp echo服务器与C中的多线程支持和用java编写的客户端,都使用套接字进行通信。通信开始很好,但不知何故,在服务器和客户端之间传递的字符串在尝试几次之后开始“损坏”(添加新的行字符或发送的旧消息片段)。 我搜索了论坛,并认为问题是C的空字符,但在Java中删除它根本没有任何区别。 这里是为C服务器代码:错误的通信c服务器和java客户端

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <linux/limits.h> 
#include <sys/types.h>   /* See NOTES */ 
#include <sys/socket.h> 
#include <errno.h> 
#include <netinet/in.h> 
#include <time.h> 
#include <stdlib.h> 
#include <limits.h> 
#include <unistd.h> 
#include <arpa/inet.h> 
#include <pthread.h> 

struct message { 
    int operacion; 
    int dato; 
}; 
int max_attempts; 

int obtenerMaxAttempts() { 
    FILE *fp; 
    fp = fopen("server.conf", "r"); 
    if (fp == NULL) { 
     perror("Error abriendo fichero"); 
     printf("Errno:%d", errno); 
    } 
    char line[LINE_MAX]; 
    char *aux; 
    while (fgets(line, LINE_MAX, fp) != NULL) { 
     aux = strtok(line, " "); 
     if (strcmp(aux, "maxAttempts") == 0) { 
      aux = strtok(NULL, " "); 
      max_attempts = atoi(aux); 
     } 
    } 
    return (max_attempts); 

} 

int obtenerPuerto() { 
    in_port_t puerto; 
    FILE *fp; 
    fp = fopen("server.conf", "r"); 
    if (fp == NULL) { 
     perror("Error abriendo fichero"); 
     printf("Errno:%d", errno); 
    } 
    char line[LINE_MAX]; 
    char *aux; 
    while (fgets(line, LINE_MAX, fp) != NULL) { 
     aux = strtok(line, " "); 
     if (strcmp(aux, "port") == 0) { 
      aux = strtok(NULL, " "); 
      puerto = atoi(aux); 
     } 
    } 
    return (puerto); 
} 



void *eco(void *new_sockfd) { 
    int socket = *((int *) new_sockfd); 
    free(new_sockfd); 

    int longitud; 
    char *mensaje_recv, *mensaje_env; 
    mensaje_recv = malloc(100 * sizeof (char)); 
    mensaje_env=malloc(100 * sizeof (char)); 
    while (1) { 
     longitud = recv(socket, (void *) mensaje_recv, 100, 0); 
     printf("Mensaje recibido del cliente: %s", mensaje_recv); 
     strcpy(mensaje_env,mensaje_recv); 
     printf("Mensaje enviado al cliente: %s", mensaje_env); 
     send(socket, (void *) mensaje_env, sizeof (mensaje_env), 0); 
     /* Cerrar el socket */ 
    } 
} 

/* Función principal del servidor */ 
int main(int argc, char *argv[]) { 
    pthread_t idHilo; 
    int error; 
    struct sockaddr_in entrada; 
    entrada.sin_family = AF_INET; 
    entrada.sin_addr.s_addr = htonl(INADDR_ANY); 
    entrada.sin_port = htons(obtenerPuerto()); 

    /* Comprueba que servidorTCP tiene 1 argumento (servidorTCP)*/ 
    if (argc != 1) { 
     printf("Número de parámetros inválido.\n Sintaxis: servidorTCP \n"); 
     exit(EXIT_FAILURE); 
    } 
    /* Creación del socket TCP */ 
    int socketid = socket(AF_INET, SOCK_STREAM, 0); // SOCK_STREAM(conexión tcp, mirar documentación de socket()) 
    if (socketid == -1) { 
     perror("Error creando el socket"); 
     printf("Errno=%d\n", errno); 
     exit(EXIT_FAILURE); 
    } 
    /************************************************************************************/ 
    /* Preparar un nombre local en el puerto especificado: El nombre local 
    */ 
    /* se prepara con la propia dirección de Internet que la sabe el sistema, 
    */ 
    /* y el puerto se obtiene del parámetro recibido 
    */ 
    /************************************************************************************/ 
    /* Asigna nombre local al socket: Asignación de una dirección local 
    */ 
    if (bind(socketid, (struct sockaddr*) &entrada, sizeof (entrada)) == -1) { 
     perror("Error asignando nombre de socket"); 
     printf("Errno=%d\n", errno); 
     exit(EXIT_FAILURE); 
    } 
    int new_sockfd; 
#define max_queue 10 
    /* Esperar el establecimiento de alguna conexión */ 
    if (listen(socketid, max_queue) == -1) { 
     perror("Error habilitando socket para conexiones"); 
     printf("Errno=%d\n", errno); 
     exit(EXIT_FAILURE); 
    } 
    struct sockaddr_in remote_addr; 
    int addrlen; 
    addrlen = sizeof (struct sockaddr_in); 
    while (1) { 

     new_sockfd = accept(socketid, (struct sockaddr *) &remote_addr, &addrlen); 
     if (new_sockfd == -1) { 
      perror("Error aceptando la conexión"); 
      printf("Errno=%d\n", errno); 
      exit(EXIT_FAILURE); 
     } 
     int *numero = malloc(sizeof (int)); 
     *numero = new_sockfd; 
     //error = pthread_create(&idHilo, NULL, juego, (void *) numero); 
     error = pthread_create(&idHilo, NULL, eco, (void *) numero); 
     if (error != 0) { 
      perror("No puedo crear thread"); 
      exit(EXIT_FAILURE); 
     } 
    } 
    /* Recibir el mensaje */ 

} 

这里是Java客户端代码:

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.io.PrintWriter; 
import java.net.*; 

/** 
* 
* @author obok 
*/ 
public class clienteTCP { 

    public static void main(String[] args) throws IOException { 
     /** 
     * Comprobamos el número de parámetros 
     * 
     */ 
     System.out.println(args); 
     System.out.println(args.length); 
     if (args.length != 2) { 
      System.out.println("Número de parámetros inválido"); 
      System.out.println("Sintaxis: clienteTCP <dirección> <puerto>"); 
      return; 
     } 
     int puerto; 
     puerto = Integer.parseInt(args[1]); 
     InetAddress direccion = null; 
     try { 
      direccion = InetAddress.getByName(args[0]); 
     } catch (UnknownHostException ex) { 
      //Logger.getLogger(clienteTCP.class.getName()).log(Level.SEVERE, null, ex); 
      System.out.println("La dirección no es correcta."); 
     } 

     Socket socket = null; 

     System.out.println("Dirección:" + direccion + " Puerto: " + puerto); 
     try { 
      socket = new Socket(direccion, puerto); 
     } catch (IOException ex) { 
      System.out.println("Error de entrada salida creando el socket."); 
      return; 
      //Logger.getLogger(clienteTCP.class.getName()).log(Level.SEVERE, null, ex); 
     } 
     BufferedReader in; 
     String mensaje; 
     mensaje = ""; 
     String mensaje2; 
     in = new BufferedReader(new InputStreamReader(System.in)); 
     //DataOutputStream outToServer = new DataOutputStream(socket.getOutputStream()); 
     PrintWriter outToServer = new PrintWriter(socket.getOutputStream(),true); 
     BufferedReader inFromServer = new BufferedReader(new InputStreamReader(
       socket.getInputStream())); 
     while (!mensaje.equalsIgnoreCase("salir")) { 
      System.out.println("Introduzca mensaje: "); 
      mensaje = in.readLine(); 
      System.out.println("Mensaje enviado al servidor: "+mensaje); 
      outToServer.println(mensaje); 
      //outToServer.writeBytes(mensaje+"\n"); 
      mensaje2 = inFromServer.readLine(); 
      mensaje2= mensaje2.replaceAll("/0", ""); 
      System.out.println("Mensaje recibido del servidor: "+ mensaje2); 

     } 
     socket.close(); 
    } 

我也试图调试在服务器(使用gdb),并且客户端(与NetBeans集成的Java调试器),但我无法弄清楚他们之间出了什么问题。任何帮助将非常感激。

在C代码中,funcion eco没有初始化malloc分配的接收缓冲区,并且在接收下一条消息之前也不重新初始化缓冲区。在阅读每条消息之前,您应该用零覆盖缓冲区。

+0

这就是问题:)。我倾向于用“java方式”思考更多的字符串,而不是像char数组。 C新手错误。我现在正在做一个memset(mensaje_env,'/ 0',100)将所有的缓冲区设置为空。另外(谢谢@TemporaryNickName)阅读像字节这样的信息给了我更多的工作*。 – user2329051 2013-04-28 15:31:35

我的第一个建议是检查您的当前端口是否被任何其他应用程序使用。简单的做法是构建一个回显服务器(例如,不是严格意义上的回显服务器,但是)并尝试连接并查看它是否成功连接到对方。

//Simple echo server 
ServerSocket welcomeSocket = new ServerSocket(//your port); 
Socket connectionSocket = welcomeSocket.accept(); 
System.out.println("Connection successful"); 

的第二个建议是,我注意到你正在使用的BufferedReader和

mensaje = in.readLine(); 

readline的功能。如果你的C服务器没有发送没有以\ n [新行]结尾的字符串,那么它就不会读取和阻止。那么我建议你使用

DataInputStream 

和(字节[])或读取(字节[])每读每一个指定缓冲区大小,使用的readFully。我希望这是有帮助的。

+0

使用的端口是6256,其他任何人都没有使用该端口(无论如何使用netstat),但我会尝试您的两条建议并通知您。非常感谢。 – user2329051 2013-04-28 13:17:32

+0

不用担心= D祝你好运! – Jason 2013-04-28 13:30:56

+0

因为你们俩都是啤酒:D // @Nemanja – user2329051 2013-04-28 15:44:44