简体   繁体   中英

Error communicating a c server and a java client

I'm trying to make a little tcp echo server with multithread support in C and a client written in java, both communicating using sockets. The communication starts just fine but somehow the strings passed between the server and the client start to get "corrupted" after a couple of tries (adding new line characters or pieces of old messages sent). I've searched the forum and thought the problem was the null character of C, but removing it in java makes no difference at all. Here is the code for the C server:

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

}

And here is the code for the java client:

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

I also tried to debug both the server (with gdb), and the client (with netbeans integrated java debugger) but I'm not able to figure out what is going wrong between them. Any help would be very much appreciated.

In C code, funcion eco, you do not initialize receive buffer allocated with malloc, and you also don't reinitialize buffer before receiving next message. Before reading each message you should overwrite buffer with zeros.

My first suggestion is check if your current port is used by any other applications. Simple way doing it is build an echo server (example is not strictly an echo server, but) and attempt a connection and see if it successfully connects to each others.

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

Second suggestion is I noticed that you are currently using BufferedReader and

  mensaje = in.readLine();

the readline function. If your C server is not sending strings that aren't ended by \\n [new lines], then it simply won't read and block. Then I suggest you to use

DataInputStream

And use readFully(byte[]) or read(byte[]) by specifying buffer size per each read. I hope this is helpful.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM