Witam,
Mam problem z komunikacją serwer - klient. Mianowicie chodzi mi o to że nie mam pojęcia w jaki sposób mam zaimplementować przesyłanie plików po przez enkapsulację danych i podzielenie pliku na mniejsze pakiety o rozmiarze nie większym niż 512 bajtów. Program w zależności od wyboru użytkownika ma przesyłać tekst lub plik. Z przesyłaniem tekstu jakoś sobie poradziłem (chociaż nie wiem czy dobrze), ale z przesyłaniem pliku mam problem. Komunikacje klient-serwer zrobiłem na podstawie windowsowego tutoriala: https://msdn.microsoft.com/pl-pl/library/windows/desktop/ms738545(v=vs.85).aspx
Poniżej zamieszczam kod źródłowy klas CSerwer i CClient wraz z mainami:
CClient
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <cstdint>
#include <fstream>
// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
#define DEFAULT_BUFLEN 512
//#define DEFAULT_PORT "10000"
struct frame_t
{
uint8_t type;
uint8_t res;
uint16_t len;
uint8_t data[508];
};
class CClient
{
uint8_t * bytes_to_send;
SOCKET ConnectSocket;
int iResult;
public:
CClient();
bool Connect(const char * addr, const char * port);
bool Disconnect();
~CClient();
int Send(char * sendbuf);
int Recieve(char * recvbuf);
bool sendFile(const char * filename);
};
#include "CClient.h"
size_t capsulate_data(uint8_t * bytes, const frame_t &frame)
{
bytes[0] = frame.type;
bytes[1] = frame.res;
memcpy(&bytes[2], (uint8_t *)&frame.len, 2);
memcpy(&bytes[4], frame.data, frame.len);
return frame.len + 4;
}
CClient::CClient()
{
WSADATA wsaData;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
//return ;
}
}
bool CClient::Connect(const char * addr, const char * port)
{
struct addrinfo *result, *ptr, hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo(addr, port, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return false;
}
// Attempt to connect to an address until one succeeds
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
//return false;
}
// Connect to server.
iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return false;
}
return true;
}
bool CClient::Disconnect()
{
char * info = "Client has been disconnected\n";
send(ConnectSocket, "Client has been disconnected\n",strlen(info) + 1, 0);
// Send an initial buffer
iResult = send(ConnectSocket, info, (int)strlen(info) + 1, 0);
if (iResult == SOCKET_ERROR) {
printf("Client is not connected with Server.\n");
WSACleanup();
return false;
}
// cleanup
closesocket(ConnectSocket);
WSACleanup();
return true;
}
CClient::~CClient()
{
iResult = shutdown(ConnectSocket, SD_SEND);
closesocket(ConnectSocket);
WSACleanup();
/*if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d \n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
}*/
}
int CClient::Send(char * sendbuf)
{
frame_t frame;
frame.type = 1; //dane tekstowe
frame.len = (int)strlen(sendbuf) + 1;
memcpy(frame.data, sendbuf, frame.len);
bytes_to_send = new uint8_t[frame.len + sizeof(frame_t)];
memcpy(bytes_to_send, &frame, frame.len);
size_t il_do_wyslania = capsulate_data(bytes_to_send, frame);
// Send an initial buffer
iResult = send(ConnectSocket,(const char *)bytes_to_send, il_do_wyslania, 0);
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
delete[] bytes_to_send;
WSACleanup();
return 1;
}
printf("Bytes Sent: %ld\n", iResult);
delete[] bytes_to_send;
return 0;
}
int CClient::Recieve(char * recvbuf)
{
int recvbuflen = DEFAULT_BUFLEN;
// Receive until the peer closes the connection
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if (iResult > 0)
printf("Bytes received: %d\n", iResult);
if (iResult == 0)
printf("Connection closed\n");
return 0;
}
bool CClient::sendFile(const char * filename)
{
std::ifstream file;
file.open(filename, std::ios::in | std::ios::binary);
if (!file.is_open())
{
printf("File does not exist!\n");
return false;
}
if (file)
{
file.seekg(0, file.end);
int length = file.tellg();
file.seekg(0, file.beg);
bytes_to_send = new uint8_t[length + sizeof(frame_t)];
printf("Reading %d bytes...\n", length);
frame_t frame;
frame.type = 2; //plik
frame.len = length;
memcpy(&frame.data, filename, strlen(filename) + 1);
file.read((char*)bytes_to_send, length);
size_t il_do_wyslania = capsulate_data(bytes_to_send, frame);
int nr_ramki = 0;
int il_byt_wysl = 0;
while (il_byt_wysl < il_do_wyslania)
{
//budowanie ramki
frame.type = 2; //dane punktów
frame.res = nr_ramki;
frame.len = il_do_wyslania - il_byt_wysl;
if (frame.len > 508)
frame.len = 508;
memcpy(frame.data, (uint8_t *)bytes_to_send + il_byt_wysl, frame.len);
//kapsulacja danych
size_t il_do_wyslania = capsulate_data(bytes_to_send, frame);
// Send an initial buffer
iResult = send(ConnectSocket, (const char *)bytes_to_send, il_do_wyslania, 0);
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
delete[] bytes_to_send;
WSACleanup();
return 1;
}
il_byt_wysl += 508;
nr_ramki++;
}
printf("Bytes Sent: %ld\n", iResult);
}
delete[] bytes_to_send;
return 0;
}
CSerwer:
#pragma once
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <cstdint>
// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")
// #pragma comment (lib, "Mswsock.lib")
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "10000"
class CSerwer
{
WSADATA wsaData;
int iResult;
SOCKET ListenSocket;
SOCKET ClientSocket;
struct addrinfo *result;
struct addrinfo hints;
struct frame_t
{
uint8_t type;
uint8_t res;
uint16_t len;
uint8_t data[508];
};
public:
CSerwer();
~CSerwer();
int Accept();
int Echo();
void Shutdown();
void Loop();
};
#include "CSerwer.h"
#include <fstream>
CSerwer::CSerwer()
{
ListenSocket = INVALID_SOCKET;
ClientSocket = INVALID_SOCKET;
result = NULL;
//struct addrinfo *result = NULL;
struct addrinfo hints;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
//return;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
//return;
}
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("listen socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
//return;
}
// Setup the TCP listening socket
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
//return;
}
freeaddrinfo(result);
}
CSerwer::~CSerwer()
{
closesocket(ListenSocket);
closesocket(ClientSocket);
WSACleanup();
}
int CSerwer::Accept()
{
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 0;
}
// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return -1;
}
return 1;
}
int CSerwer::Echo()
{
int iSendResult;
char recvbuf[DEFAULT_BUFLEN];
iResult = recv(ClientSocket, recvbuf, DEFAULT_BUFLEN, 0);
if (iResult > 0) {
frame_t frame;
memcpy(&frame, recvbuf, sizeof(frame_t));
unsigned int downloaded = iResult;
while (downloaded < frame.len) {
iResult = recv(ClientSocket, recvbuf + downloaded, DEFAULT_BUFLEN, 0);
if (iResult == 0)
break;
else if (iResult < 0)
return 0;
downloaded += iResult;
}
if (frame.type == 1)
{
if (frame.data[0] == 'Q')
{
printf("Klient zakonczyl polaczenie z serwerem\n");
closesocket(ClientSocket);
WSACleanup();
return 0;
}
printf("Przeslano slowo: %s\n", frame.data);
printf("Bytes received: %d\n", iResult);
iSendResult = send(ClientSocket, recvbuf, frame.len , 0);
if (iSendResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 0;
}
printf("Bytes sent: %d\n", iSendResult);
}
else if (frame.type == 2)
{
int nr_ramki = 0, offset = 0;
bool something_recv = false;
while (true)
{
if (iResult == 512)
{
nr_ramki = recvbuf[0];
offset = nr_ramki * 511;
memcpy((uint8_t *)(frame.res)+offset, &recvbuf[1], 511);
something_recv = true;
}
if (nr_ramki == 0 && something_recv)
{
break;
}
}
std::ofstream file((const char *)frame.data, std::ios::out | std::ios::binary);
file.write(recvbuf + sizeof(frame_t), frame.len);
iSendResult = send(ClientSocket, (const char *)frame.data, sizeof(frame.data), 0);
if (iSendResult == SOCKET_ERROR) {
return 0;
}
printf("Saving %d bytes -> file ( %s )\n", frame.len, frame.data);
printf("Bytes sent: %d\n", iSendResult);
}
}
else if (iResult == 0)
{
printf("Connection closing...\n");
return 0;
}
else {
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 0;
}
return 1;
}
void CSerwer::Shutdown()
{
// shutdown the connection since we're done
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
}
//closesocket(ClientSocket);
//WSACleanup();
}
void CSerwer::Loop()
{
int check = 1;
do
{
printf("Listening for client...\n");
if (Accept())
printf("Client has been connected!\n");
else
printf("Client has been disconnected!\n");
do
{
check = Echo();
} while (check > 0);
} while (check > 0);
printf("Shut down\n");
Shutdown();
}