Проблема отправки / получения данных с сервера Java клиента C ++ - PullRequest
0 голосов
/ 21 сентября 2018

Я создал простой Java-клиент и сервер C ++.Я пытаюсь передать некоторые данные с клиента на сервер.Проблема в том, что когда сервер получает данные, он показывает некоторые плохие символы, а также когда сервер возвращает какой-то ответ клиенту java, я снова вижу эти плохие символы.Не могли бы вы помочь мне решить эту проблему ..

Java-клиент

 public Client(String host, int port) {
        try {
            String serverHostname = new String(host);

            System.out.println("Connecting to host " + serverHostname + " on port " + port + ".");

            Socket echoSocket = null;
            PrintWriter out = null;
            BufferedReader in = null;

            try {
                echoSocket = new Socket(serverHostname, port);
                out = new PrintWriter(echoSocket.getOutputStream(), true);
                in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
            } catch (UnknownHostException e) {
                System.err.println("Unknown host: " + serverHostname);
                System.exit(1);
            } catch (IOException e) {
                System.err.println("Unable to get streams from server");
                System.exit(1);
            }

            /** {@link UnknownHost} object used to read from console */
            BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));

            while (true) {
                System.out.print("client: ");

                String userInput = stdIn.readLine();
                /** Exit on 'q' char sent */
                if ("q".equals(userInput)) {
                    break;
                }
                out.println(userInput);
                System.out.println("server: " + in.readLine());
            }

            /** Closing all the resources */
            out.close();
            in.close();
            stdIn.close();
            echoSocket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

c ++ сервер

int main()
{
    SOCKET ConSock;
    SOCKET ListenSock;
    SOCKADDR_IN address;
    int addsize = sizeof(address);

    long ok;
    char MESSAGE[200];

    WSAData WSD;
    WORD DllVersion = MAKEWORD(2, 1);

    ok = WSAStartup(DllVersion, &WSD);

    ConSock = socket(AF_INET,SOCK_STREAM,NULL);
    address.sin_addr.s_addr = inet_addr("10.64.15.3");
    address.sin_family = AF_INET;
    address.sin_port = htons(10102);

    ListenSock = socket(AF_INET,SOCK_STREAM,NULL);

    bind(ListenSock,(SOCKADDR*)&address,sizeof(address));
    listen(ListenSock,SOMAXCONN);

    cout<<"Waiting for connection\n";

    while(1)
    {
        if(ConSock = accept(ListenSock,(SOCKADDR*)&address,&addsize))
        {

            ok = recv(ConSock,MESSAGE,sizeof(MESSAGE),NULL);

            string msg;
            msg = MESSAGE;

            cout<<"Client says:\t"<<msg;
            string reply;
            cout<<"\nEnter reply:";
            cin>>reply;

            const char* rep = reply.c_str();

            ok = send(ConSock,rep,1024,NULL);

        }

    }
}

Вот изображение ввода, которое я получаю от клиента: образ сервера c ++

Ответы [ 2 ]

0 голосов
/ 21 сентября 2018

Вы просто не проверяете длину буферов где-либо на стороне C ++.

в этой части

        ok = recv(ConSock,MESSAGE,sizeof(MESSAGE),NULL);

        string msg;
        msg = MESSAGE;

вы просто назначаете msg все байты, пока он не увидит0, но вы никогда не завершали его нулем, поэтому он просто печатает случайные вещи в памяти.Это, кстати, также потенциальное переполнение буфера.

Что-то более подходящее может быть

        auto byte_count = recv(ConSock,MESSAGE,sizeof(MESSAGE),NULL);

        string msg;
        if(byte_cout > 0 )
        {
            msg.assign(MESSAGE, byte_count);
        }

Нечто подобное происходит при отправке всего буфера здесь:

        cin>>reply;
        const char* rep = reply.c_str();
        ok = send(ConSock,rep,1024,NULL);

У вас также есть потенциальное переполнение буфера, так как вы всегда отправляете 1024 байта независимо от размера буфера.

Что-то вроде этого может быть лучше

        cin>>reply;
        ok = send(ConSock,reply.c_str(),reply.size(),NULL);

Редактировать: Полные программы с чуть более четко определенным состоянием «конец сообщения» будут выглядеть примерно так:

Java

public Client(String host, int port) {
    try {
        String serverHostname = new String(host);

        System.out.println("Connecting to host " + serverHostname + " on port " + port + ".");

        Socket echoSocket = null;
        PrintWriter out = null;
        BufferedReader in = null;

        try {
            echoSocket = new Socket(serverHostname, port);
            out = new PrintWriter(echoSocket.getOutputStream(), true);
            in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
        } catch (UnknownHostException e) {
            System.err.println("Unknown host: " + serverHostname);
            System.exit(1);
        } catch (IOException e) {
            System.err.println("Unable to get streams from server");
            System.exit(1);
        }

        /** {@link UnknownHost} object used to read from console */
        BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));

        while (true) {
            System.out.print("client: ");

            String userInput = stdIn.readLine();
            /** Exit on 'q' char sent */
            if ("q".equals(userInput)) {
                break;
            }
            out.println(userInput);
            //send a newline as a marker for "message is over"
            out.write('\n');
            System.out.println("server: " + in.readLine());
        }

        /** Closing all the resources */
        out.close();
        in.close();
        stdIn.close();
        echoSocket.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

C ++ сторона

int main()
{
    SOCKET ConSock;
    SOCKET ListenSock;
    SOCKADDR_IN address;
    int addsize = sizeof(address);

    long ok;
    char MESSAGE[200];

    WSAData WSD;
    WORD DllVersion = MAKEWORD(2, 1);

    ok = WSAStartup(DllVersion, &WSD);

    ConSock = socket(AF_INET,SOCK_STREAM,NULL);
    address.sin_addr.s_addr = inet_addr("10.64.15.3");
    address.sin_family = AF_INET;
    address.sin_port = htons(10102);

    ListenSock = socket(AF_INET,SOCK_STREAM,NULL);

    bind(ListenSock,(SOCKADDR*)&address,sizeof(address));
    listen(ListenSock,SOMAXCONN);

    cout<<"Waiting for connection\n";

    while(1)
    {
        if(ConSock = accept(ListenSock,(SOCKADDR*)&address,&addsize))
        {
            string msg;
            bool message_finished = false;
            //read into msg until we read a newline at the end or we get an error
            while(!message_finished)
            {
                auto length_read = recv(ConSock,MESSAGE,sizeof(MESSAGE),NULL);
                if(length_read > 0)
                {
                    msg.append(MESSAGE,length_read);
                    message_finished = msg[msg.size()-1] == '\n';
                }
                else if(length_read < 0)
                {
                   //don't continue to just endlessly loop on error
                   message_finished = true;
                }
            }

            cout<<"Client says:\t"<<msg;
            string reply;
            cout<<"\nEnter reply:";
            cin>>reply;
            //append a newline at the end to mark the end of the message
            reply+='\n';
            ok = send(ConSock, reply.c_str(), reply.size(),NULL);

        }

    }
}
0 голосов
/ 21 сентября 2018

Символ Java составляет два байта.Если вы закодируете / расшифруете его при выходе из него, оно, вероятно, будет работать (учитывая, что вы правильно указали длину строки, я не проверял).

StandardCharsets.ISO_8859_1.encode(chars).array() -> byte array
StandardCharsets.ISO_8859_1.decode(bytes).array() -> char array

Следующая вещь, которая сломается, как тольковы начинаете отправлять вещи, отличные от текста, или выбираете отправлять юникод и использовать wstring на стороне C ++ - Java использует сетевой порядок байтов, C ++ - порядок байтов хоста (противоположный Java на x86).Это одна из причин.

Последний совет - сначала сделайте так, чтобы он работал на Java-Java или C ++ - C ++ (на каком языке вы говорите лучше), а затем переключитесь на отладку микса Java-C ++.

...