Обмен данными между сокетами

135
22 ноября 2018, 07:20

Написал сокет-сервер на python (ubuntu), а клиента на c++ (windows). Проблема в том, что на сервере функция recv требует оповещение об закрытиии сокета (shutdown) от клиента, иначе на этом месте скрипт останавливается. Если же я вызову shutdown на стороне клиента, сервер примет сообщение и отправит ответное, но клиент-сокет больше не сможет ни отправлять, ни получать данные (из-за этого shutdown). А мне нужно обмениваться данными в цикле.

Вот примерно так:

клиент:

 1.инициализация сокета
 2. подключение к серверу
 3. отправка данных
 4. получение ответа от сервера
 5. отправка данных
 6. получение ответа от сервера  ...
 55. закрытие соединения

server.py:

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((host, port))
sock.listen(10)
while 1:
    conn, addr = sock.accept()
    print('new connection from ' + addr[0] + ":" + str(addr[1]))
    data = bytearray()
    while 1:
        while 1:
            chunk = conn.recv(128)
            if not chunk:
                break
            else:
                data += chunk
        print(str(len(data)) + " bytes received (" + data.decode('ascii', 'strict') + ")")
        date = strftime("%Y-%m-%d %H:%M:%S", gmtime())
        bytes_len = conn.send(date.encode('ascii'))
        print(str(bytes_len) + " bytes sent")
    print('closing the connection..')
    conn.close()
sock.close()

client.exe:

int send_data(SOCKET sock, const char* data, int datalen)
{
    int bytes_len = send(sock, data, datalen, 0);
    if (bytes_len < 0) {
        return -1;
    }
    /*if (shutdown(sock, SD_SEND) < 0) {
        return -1;
    }*/
    return bytes_len;
}
int recv_data(SOCKET sock, char* buf)
{
    log("0");
    int recvlen = 0;
    char chunk[128];
    memset(chunk, 0, sizeof(chunk));
    do {
        log("1");
        int len = recv(sock, chunk, sizeof(chunk), 0);
        log("2");
        if (len == -1)
            return -1;
        if (len == 0)
        {
            /*if (shutdown(sock, SD_RECEIVE) < 0) {
                return -1;
            }*/
            return recvlen;
        }
        memcpy(buf + recvlen, chunk, len);
        memset(chunk, 0, sizeof(chunk));
        recvlen += len;
    } while (true);
}
void force()
{
    char* ip = "";
    int port = 0;
    int result;
    WSADATA wsaData;
    log("socket startup..");
    result = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (result != 0) {
        log("wsastartup failed: %d", result);
        return;
    }
    log("creating socket..");
    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock == INVALID_SOCKET) {
        log("error creating socket: %d", WSAGetLastError());
        WSACleanup();
        return;
    }
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(struct sockaddr_in));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(ip);
    addr.sin_port = htons(port);
    log("connecting to %s:%d", ip, port);
    result = connect(sock, (sockaddr *)&addr, sizeof(addr));
    if (result == SOCKET_ERROR) {
        log("Unnable to connect to server: %d", WSAGetLastError());
        WSACleanup();
        return;
    }

    for (int i = 0; i < 10; i++)
    {
        string msg = "hello from windows " + to_string(i);
        int bytes_len = send_data(sock, msg.c_str(), msg.length());
        if (bytes_len < 0)
        {
            log("Error sending data: %d", WSAGetLastError());
            closesocket(sock);
            WSACleanup();
            return;
        }
        log("%d bytes sent..", bytes_len);
        char buf[1024];
        memset(buf, 0, sizeof(buf));
        bytes_len = recv_data(sock, buf);
        if (bytes_len < 0)
        {
            log("Error receiving data: %d", WSAGetLastError());
            closesocket(sock);
            WSACleanup();
            return;
        }
        log("%d bytes received (%s)", bytes_len, buf);
    }
    log("socket closing..");
    closesocket(sock);
    log("wsa cleanup..");
    WSACleanup();
    return;
}
Answer 1

Сервер ожидает, что ему придет от клиента 128 байт данных:

chunk = conn.recv(128)

Клиент отправляет явно меньше:

string msg = "hello from windows " + to_string(i);

Вызов conn.recv(128) - блокирующий, т.е., если в буфере сокета нет данных - он будет ждать.

Спасибо @jfs за замечание

Когда Вы вызываете shutdown(sock, SD_RECEIVE) отправляется пакет с сегментом FIN (на самом деле их отправляется несколько) - и тогда read возвращает ноль (EOF - с данного сокета вы больше не можете читать данные):

if not chunk:
                break

Что в итоге позволяет выйти из цикла.

READ ALSO
Ошибка class not found

Ошибка class not found

При компиляции кода в IntelliJ IDEA всё работает отлично, но как только вывожуjar и пытаюсь запустить его, пишет ошибку:

168
Java, массив и двойной цикл for

Java, массив и двойной цикл for

Есть массив, нужно каждый элемент массива прогнать через цикл с добавлением цифрПроблема в том, что код прогоняет только первый элемент массива

158
Как получить картинку их аудиофайла в java?

Как получить картинку их аудиофайла в java?

Хочу сделать плеер и вот пытаюсь выловить картинку из mp3 файлаПытался установить mp3agic и с помощью него извлечь, но при установки вылезают...

164
Не могу прервать выполнение Phantomjs в Java

Не могу прервать выполнение Phantomjs в Java

У меня есть интерфейс в котором есть кнопка старт, она запускает Phantomjs, но в момент запуска, интерфейс становиться недоступным, до тех пор...

151