E
E
Elnurhan2020-06-14 19:24:46
C++ / C#
Elnurhan, 2020-06-14 19:24:46

Why is the string split when transmitted over the socket?

There is a task to write an application (client-server) for transferring binary files. Wrote the following implementation:

Client

#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <cstring>

#define IP "127.0.0.1"
#define PORT 27015
#define BUFSIZE 4096

#pragma comment(lib, "Ws2_32.lib")


void sendFile(SOCKET& client_socket, char* buf, char* filepath);


int main()
{
  WSADATA d;
  int result;
  result = WSAStartup(MAKEWORD(2,2), &d);
  if (result != 0)
  {
    std::cout << "Error WSAStartup: " << result << "\n";
    return 1;
  }

  SOCKET clientSocket = INVALID_SOCKET;
  clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (clientSocket == INVALID_SOCKET)
  {
    std::cout << "Error socket(): " << WSAGetLastError() << "\n";
    WSACleanup();
    return 1;
  }

  sockaddr_in clientService;
  clientService.sin_family = AF_INET;
  clientService.sin_addr.s_addr = inet_addr(IP);
  clientService.sin_port = htons(PORT);

  result = connect(
        clientSocket,
        reinterpret_cast<SOCKADDR*>(&clientService),
        sizeof(clientService)
      );
  if (result != 0)
  {
    std::cout << "Connection error: " << WSAGetLastError() << "\n";
    WSACleanup();
    return 1;
  }

  const int N = 100;
  char buf[BUFSIZE], filepath[N];
  int r;
  do
  {
    std::cin >> filepath;
    sendFile(clientSocket, buf, filepath);

    if (r > 0)
      std::cout << "Receive: " << buf << "\n";
    else if (r == 0)
      std::cout << "Connection lost\n";
    else
      std::cout << "Recv error: " << WSAGetLastError() << "\n";
  } while (r > 0);

  closesocket(clientSocket);
  WSACleanup();
  return 0;
}

void sendFile(SOCKET& clientSocket, char* buf, char* filepath)
{
  FILE *f;
  f = fopen(filepath, "rb");

  int readed;

  if (f != 0)
  {
    while((readed = fread(buf, 1, sizeof(buf), f)) != 0)
    {
      send(clientSocket, (char*)buf, readed, 0);
    }
  }
}

server:
#define _WIN32_WINNT 0x501

#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>

#define DEFAULT_PORT "27015"
#define DEFAULT_BUFLEN 4096

#pragma comment(lib, "Ws2_32.lib")

int main()
{
    int iResult;
    WSAData d;

    // Данные для сокета
    iResult = WSAStartup(MAKEWORD(2,2), &d);
    if (iResult != 0)
    {
        std::cout << "Error at WSAStartup: " << iResult;
        return 1;
    }

    struct addrinfo *result = nullptr, hints;
    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
    if (iResult != 0)
    {
        std::cout << "getaddrinfo error: " << iResult;
        WSACleanup();
        return 1;
    }

    // Creating socket
    SOCKET listenSocket = INVALID_SOCKET;
    listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
    if (listenSocket == INVALID_SOCKET)
    {
        std::cout << "Error at socket(): " << WSAGetLastError();
        freeaddrinfo(result);
        WSACleanup();
        return 1;
    }

    iResult = bind(listenSocket, result->ai_addr, result->ai_addrlen);
    if (iResult == SOCKET_ERROR)
    {
        std::cout << "Error at bind(): " << WSAGetLastError();
        freeaddrinfo(result);
        WSACleanup();
        return 1;
    }

    freeaddrinfo(result);

    if (listen(listenSocket, SOMAXCONN) == SOCKET_ERROR)
    {
        std::cout << "Listen error: " << WSAGetLastError();
        closesocket(listenSocket);
        WSACleanup();
        return 1;
    }

    SOCKET ClientSocket = INVALID_SOCKET;

    ClientSocket = accept(listenSocket, NULL, NULL);
    if (ClientSocket == INVALID_SOCKET)
    {
        std::cout << "Accept failed with error: " << WSAGetLastError();
        closesocket(listenSocket);
        WSACleanup();
        return 1;
    }

    // data trade
    char recvbuf[DEFAULT_BUFLEN];
    int iSendResult;
    int recvbuflen = DEFAULT_BUFLEN;
    
    do
    {
        iResult = recv(ClientSocket, recvbuf, sizeof(recvbuflen), 0);
        FILE *f = fopen("output.txt", "wb");
    fwrite(recvbuf, 1, iResult, f);
        if (iResult > 0)
        {
            std::cout << "Recv: " << recvbuf << "\n";

            iSendResult = send(ClientSocket, recvbuf, recvbuflen, 0);
            if (iSendResult == SOCKET_ERROR)
            {
                std::cout << "Send failed with error: " << WSAGetLastError();
                closesocket(ClientSocket);
                WSACleanup();
                return 1;
            }
        }
        else if (iResult == 0)
            std::cout << "Connection closed...\n";
        else
        {
            std::cout << "Recv error: " <<WSAGetLastError();
            closesocket(ClientSocket);
            return 1;
        }
    } while(iResult > 0);
}

The Client must enter the path to the file to be transferred. In the same directory, I have a Hello.txt file that contains "Hello, world". When transferring this file, the server receives the data as follows:

Recv: Hell

Recv: o, w

Recv: orld

And writes orld to a file. What is it connected with?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
A
Armenian Radio, 2020-06-14
@Elnurhan

Another "I did not read the manuals, pamagit" question.
Read Sneijder, J. "Efficient TCP/IP Programming".
In short, the send() and recv() functions do not guarantee that as many bytes will be written or read as you send them. You need to analyze the value returned by these functions - if it is 0 or < 0 - something has broken and you need to analyze errorno, otherwise, that's how many bytes were transferred.

M
maaGames, 2020-06-15
@maaGames

In the socket read cycle, the file is reopened for writing each time, deleting what was previously written. Open the file before the loop and close it after exiting the loop.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question