komunikacja sieciowa - przesyłanie danych w pętli

0

Nie wiem czy piszę w dobrym dziale, bo trochę dotyczy to Javy, trochę C. Otóż, mam do napisania program do komunikacji sieciowej opartej na socketach. Klienta piszę w javie, a serwer w C. Po podłączeniu klienta chciałbym przesłać mu listę stringów, które znajdują się w pliku tekstowym, a następnie klient może jeszcze coś tam sobie wysyłać/przyjmować. Próbowałem robić to w pętli, przesyłając kolejne linie, jednak mam problem z warunkiem stopu w kliencie. Za pętlą w serwerze dodałem jeszcze jednego write, który dodaje "end" i sprawdzam w kliencie czy pobrana linia to end. W serwerze wychodzi bez problemu z tej pętli, jednak w kliencie wisi na niej. Oto fragmenty kodu:
klient:

 while(!(answer = input.readLine()).equals("end")) {
        System.out.println(answer);
    }

serwer:

 char* line;
size_t len = 0;
ssize_t read;
FILE* out;
while((read = getline(&line, &len, out))!=-1){
    write(fd, line, read);
}
write(fd, "end", 3);

Nie wiem jak to inaczej rozwiązać, dlatego bardzo proszę o pomoc.

0

Nie stukaj głową w mur. Łatwiej będzie to zrobić (i czytelniej) jeśli skorzystasz z Boost.ASIO. Część Networking będzie częścią standardu C++17 (lub następnego :-) ). http://www.boost.org/doc/libs/1_63_0/doc/html/boost_asio.html

0

Tylko, że to projekt na zaliczenie i takie mam wymagania co do technologii :(

2

To twój szczęśliwy dzień:
main.c

#include <WinSock2.h>
#include <ws2tcpip.h>
#pragma comment (lib, "Ws2_32.lib")

#include <stdio.h>
#include <string.h>
#include <assert.h>

struct server_context {
    const char *port;
    SOCKET listen_socket;
};

enum server_error {
    server_failed_to_getaddrinfo = 1,
    server_failed_to_create_socket,
    server_failed_to_bind_socket,
    server_failed_to_listen,
    server_failed_to_accept
};

struct server_context create_server(const char *port, int *output_error_type, int *output_error) {
    assert(output_error_type);
    assert(output_error);

    int error = 0;

    struct addrinfo *info = 0;
    struct addrinfo hints = {
        .ai_family   = AF_INET,
        .ai_socktype = SOCK_STREAM,
        .ai_protocol = IPPROTO_TCP,
        .ai_flags    = AI_PASSIVE
    };

    struct server_context server = {
        .port = port,
        .listen_socket = INVALID_SOCKET
    };

    if(error = getaddrinfo(0, server.port, &hints, &info)) {
        *output_error_type = server_failed_to_getaddrinfo;
        *output_error = error;
        goto panic;
    }

    if(INVALID_SOCKET == (server.listen_socket = socket(info->ai_family, info->ai_socktype, info->ai_protocol))) {
        *output_error_type = server_failed_to_create_socket;
        *output_error = WSAGetLastError();
        goto panic;
    }

    if(SOCKET_ERROR == (bind(server.listen_socket, info->ai_addr, (int) info->ai_addrlen))) {
        *output_error_type = server_failed_to_bind_socket;
        *output_error = WSAGetLastError();
        goto panic;
    }

panic:
    freeaddrinfo(info);
    return server;
}

void server_listen(struct server_context *server, int *output_error_type, int *output_error) {
    if(SOCKET_ERROR == listen(server->listen_socket, SOMAXCONN)) {
        *output_error_type = server_failed_to_listen;
        *output_error = WSAGetLastError();
    }
}

SOCKET server_accept_client(struct server_context *server, int *output_error_type, int *output_error) {
    SOCKET client_socket = accept(server->listen_socket, NULL, NULL);
    if(client_socket == INVALID_SOCKET) {
        *output_error_type = server_failed_to_accept;
        *output_error = WSAGetLastError();
    }
    return client_socket;
}

void serve_file_to(SOCKET client_socket, const char *filename) {
    FILE* fp;
    char buffer[1024];
    fp = fopen(filename, "r");
    while(fgets(buffer, sizeof(buffer)/sizeof(buffer[0]), fp)) {
        printf("#sending: %s", buffer);
        send(client_socket, buffer, strlen(buffer), 0);
    }
    send(client_socket, "\n", strlen("\n"), 0);
    fclose(fp);
}

WSADATA const * wsa_startup(int *result) {
    static WSADATA wsa_data;
    int wsa_startup_errorcode = WSAStartup(MAKEWORD(2, 2), &wsa_data);
    if(result) {
        *result = wsa_startup_errorcode;
    }
    return &wsa_data;
}

int wsa_cleanup(void) {
    return WSACleanup();
}


#define GUARD(error_pointer, panic_label, expr) expr; if(error_pointer) { goto panic_label; }
int main() {

    wsa_startup(0);
    int err_type = 0, err = 0;

    puts("#create_server(...)...");
    GUARD(err_type, panic, struct server_context server = create_server("1337", &err_type, &err));
    
    puts("#server_listen(...)...");
    GUARD(err_type, panic, server_listen(&server, &err_type, &err));

    puts("#server_accept_client(...)...");
    GUARD(err_type, panic, SOCKET client_socket = server_accept_client(&server, &err_type, &err));

    //we don't need it anymore
    closesocket(server.listen_socket);

    serve_file_to(client_socket, "list.txt");

    const char *finish_connection_message = "end\n";
    send(client_socket, finish_connection_message, strlen(finish_connection_message), 0);

    shutdown(client_socket, SD_SEND);
panic:
    if(err_type) {
        fprintf(stderr, "server error: %d | %d", err_type, err);
    }
    closesocket(server.listen_socket);
    return wsa_cleanup();
}

main.java

import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;

public class Main {

    public static void main(String[] args) throws IOException {
        int port = 1337;
        String ip = "localhost";
        Socket socket = new Socket(ip, port);
        DataInputStream input = new DataInputStream(socket.getInputStream());
        //readLine zostało deprecjonowane, ale trzeba poużywać póki można :]
        for(String message; null != (message = input.readLine());) {
            //srsly, nie ma potrzeby słania takiej wiadomości
            if("end".equals(message)) {
                break;
            }
            System.out.println(message);
        }
        socket.close();
    }
}

list.txt

Pierwsze zdanie.
Jakies fajne dane.
Trzecie zdanie.
Po co komu kropka?
albo inne znaki
ehh

server stdout

#create_server(...)...
#server_listen(...)...
#server_accept_client(...)...
#sending: Pierwsze zdanie.
#sending: Jakies fajne dane.
#sending: Trzecie zdanie.
#sending: Po co komu kropka?
#sending: albo inne znaki
#sending: ehh

client stdout

Pierwsze zdanie.
Jakies fajne dane.
Trzecie zdanie.
Po co komu kropka?
albo inne znaki
ehh

1 użytkowników online, w tym zalogowanych: 0, gości: 1