2013-04-28 77 views
1

我試圖做一個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調試器),但我無法弄清楚他們之間出了什麼問題。任何幫助將非常感激。

回答

1

在C代碼中,funcion eco沒有初始化malloc分配的接收緩衝區,並且在接收下一條消息之前也不重新初始化緩衝區。在閱讀每條消息之前,您應該用零覆蓋緩衝區。

+0

這就是問題:)。我傾向於用「java方式」思考更多的字符串,而不是像char數組。 C新手錯誤。我現在正在做一個memset(mensaje_env,'/ 0',100)將所有的緩衝區設置爲空。另外(謝謝@TemporaryNickName)閱讀像字節這樣的信息給了我更多的工作自由。 – user2329051 2013-04-28 15:31:35

0

我的第一個建議是檢查您的當前端口是否被任何其他應用程序使用。簡單的做法是構建一個回顯服務器(例如,不是嚴格意義上的回顯服務器,但是)並嘗試連接並查看它是否成功連接到對方。

//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

相關問題