2013-04-28 8 views
1

C에서 소켓을 사용하여 통신하는 자바로 작성된 클라이언트에서 다중 스레드를 지원하는 작은 tcp 서버를 만들려고합니다. 통신은 잘 시작되지만 어떻게 든 서버와 클라이언트 사이에 전달 된 문자열은 두 줄의 시도 (줄 바꿈 문자 추가 또는 오래된 메시지 조각 전송) 후에 "손상"되기 시작합니다. 저는 포럼을 검색하여 문제가 C의 null 문자라고 생각했지만 Java에서 제거하면 아무런 효과가 없습니다. 여기 은 C 서버의 코드입니다C 서버와 자바 클라이언트 통신 오류가 발생했습니다.

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

} 

그리고 여기에 자바 클라이언트의 코드입니다 : 나는 또한 (GDB)와 서버 모두를 디버깅하려고

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(); 
    } 

, 클라이언트 (netbeans 통합 자바 디버거와 함께)하지만 나는 그들 사이에 무엇이 잘못되었는지 알아낼 수 없습니다. 어떤 도움이라도 대단히 감사 할 것입니다.

답변

1

C 코드의 funcion eco에서는 malloc으로 할당 된 수신 버퍼를 초기화하지 않으며 다음 메시지를 받기 전에 버퍼를 다시 초기화하지 않습니다. 각 메시지를 읽기 전에 버퍼를 0으로 덮어 써야합니다.

+0

정확히 그게 문제였다. :) 나는 "자바 방식"으로 문자열을 생각하고 char 배열을 생각하지 않는 경향이있다. C 초보자 실수. 모든 버퍼를 null로 설정하기 위해 memset (mensaje_env, '/ 0', 100)을 사용하고 있습니다. 또한 바이트와 같은 정보를 읽는 (감사합니다 @TemporaryNickName) 나는 훨씬 더 자유롭게 일할 수 있습니다. – user2329051

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 [new lines]에 의해 끝나지 않은 문자열을 보내지 않는다면 단순히 읽기와 차단 만하지 않을 것입니다. 그럼 난 당신이

DataInputStream 

를 사용하고 (바이트 []) 또는 읽기 (바이트 []) 각 읽기 당 버퍼 크기를 지정하여 내의 readFully을 사용하는 것이 좋습니다. 이것이 도움이되기를 바랍니다.

+0

사용되는 포트는 다른 어느 누구도 사용하지 않는 6256이지만 (어쨌든 netstat을 사용하고 있습니다), 귀하의 제안을 모두 시도하고 알려 드리겠습니다. 고마워. – user2329051

+0

걱정 마세요 = D 행운을 빌어 요! – Jason

+0

두 맥주 다 : D // @ 네마냐 – user2329051

관련 문제