Sockets downloading too little or too much of a webpage - c++

Why does my code only download half a webpage?? Sometimes it downloads 4x the webpage's size :S
I cannot find what is wrong which is why I'm asking. Basically, I connect to the socket, send my Request and read the response to a buffer. I tried saving it to a file and printing it to the screen but it prints and saves incomplete data or too much data. I'm not sure if its a buffer-overflow or not or what I'm doing wrong.
Any ideas?
#define _WIN32_WINNT 0x501
#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <fstream>
using namespace std;
void Get(string WebPage)
{
WSADATA wsaData;
string Address;
struct addrinfo *result;
struct sockaddr_in *sockaddr_ipv4;
char Buffer[50000] = {0};
string Header = "GET / HTTP/1.1\r\n";
Header += "Host: " + WebPage + "\r\n";
Header += "Connection: close\r\n";
Header += "\r\n";
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) return;
SOCKET Socket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
getaddrinfo(WebPage.c_str(), NULL, NULL, &result);
if (result->ai_family == AF_INET)
{
sockaddr_ipv4 = (struct sockaddr_in *) result->ai_addr;
Address = inet_ntoa(sockaddr_ipv4->sin_addr);
}
freeaddrinfo(result);
SOCKADDR_IN SockAddr;
memset(&SockAddr, 0, sizeof(SockAddr));
SockAddr.sin_port = htons(80);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = inet_addr(Address.c_str());
if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr)) == SOCKET_ERROR) return;
if (send(Socket, Header.c_str(), Header.size(), 0) == SOCKET_ERROR) return;
shutdown(Socket, SD_SEND);
std::string Response;
while(true)
{
int Val = recv(Socket, Buffer, sizeof(Buffer), 0);
if (Val == 0)
break;
else if (Val == SOCKET_ERROR)
{
cout<<"Error!";
}
else
{
Response += Buffer;
}
}
closesocket(Socket);
WSACleanup();
ofstream File;
File.open("C:/Saved.html");
File<<Response;
File.close();
}
int main()
{
Get("villavu.com");
}

Edit: recv isn't null terminating the data for you - you need to write how much data you received, not just += it.
Is there any binary data in your response? If so, the
Response += Buffer;
will stop at the first null character. I would use a vector to store the data from the recv as such:
vector<char> recvBuffer(50000);
int bytesReceived = recv(socket, recvBuffer.data(), recvBuffer.size(), 0);
//error checking
recvBuffer.resize(bytesReceived);
and again store your received data in another vector, copying it back in.
vector<char> pageContents;
pageContents.insert(pageContents.end(), recvBuffer.begin(), recvBuffer.end());
That wouldn't explain your 4x data though.
Another issue I see is that you aren't zeroing out your buffer after it is used.
IOW: You need to write how much data you received, not just += the array.

Related

linux socket lose data when a delay is added before read

I am learning linux socket programming, I expect that server can read data, even I add a delay but it just drops the buffer data, and receive the recent data, that is why, Thanks. The code has been presented.
By the way, Could you show a common practice to deal with this kind of situation?
Server side C/C++ program to demonstrate Socket programming
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#define PORT 8080
int main(int argc, char const *argv[])
{
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = {0};
const char hello[] = "Hello from server";
// Creating socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
// Forcefully attaching socket to the port 8080
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
&opt, sizeof(opt)))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// Forcefully attaching socket to the port 8080
if (bind(server_fd, (struct sockaddr *)&address,
sizeof(address)) < 0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
(socklen_t *)&addrlen)) < 0)
{
perror("accept");
exit(EXIT_FAILURE);
}
for (int i = 0;; i++)
{
sleep(5);
valread = read(new_socket, buffer, 1024);
printf("%s\n", buffer);
}
send(new_socket, hello, strlen(hello), 0);
printf("Hello message sent\n");
return 0;
}
Client side C/C++ program to demonstrate Socket programming
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string>
#include <string.h>
#define PORT 8080
int main(int argc, char const *argv[])
{
int sock = 0, valread;
struct sockaddr_in serv_addr;
const char data[] = "Hello from client";
char buffer[1024] = {0};
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Socket creation error \n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// Convert IPv4 and IPv6 addresses from text to binary form
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0)
{
printf("\nInvalid address/ Address not supported \n");
return -1;
}
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\nConnection Failed \n");
return -1;
}
for (int i = 0;; i++)
{
sleep(1);
std::string hello = std::string(data) + std::to_string(i);
if (send(sock, hello.c_str(), hello.length() + 1, 0) != hello.length() + 1)
{
printf("error send %d \n", i);
}
printf("Hello message sent %d\n", i);
}
valread = read(sock, buffer, 1024);
printf("%s\n", buffer);
return 0;
}
The problem is, that the messages get concatenated in the socket. The socket represents a byte stream. Your sender puts bytes into the stream every second. On the first iteration, it writes "Hello from client0\0" (19 bytes) to the stream.
After one second, it writes "Hello from client1\0", and then "Hello from client2\0", "Hello from client3\0" and "Hello from client4\0", Now, after 5 Seconds, 5*19 = 95 bytes are written to the byte stream.
Now, the receiver calls valread = read(new_socket, buffer, 1024);. Guess what, it reads all 95 bytes (because you specified 1024 as buffer size) and sets valread to 95.
Then you call printf("%s\n", buffer);, which only prints the first 18 bytes of buffer, because there is a '\0' as 19th byte, which terminates '%s' format. Allthough 95 bytes are received, 76 bytes are missing in the output of your program.
If you use '\n' instead of '\0' as message separator and use write(1, buffer, valread) instead of printf("%s\n") on the receiving side, you will see all your data.
std::string hello = std::string(data) + std::to_string(i) + "\n";
if (send(sock, hello.c_str(), hello.length(), 0) != hello.length()) ...
Conclusion:
Stream sockets realize byte sreams, the do not preserve message boundaries.
If message bounaries must be preserved, you need to use a protocol on top of the stream to mark your message boundaries. The proptocol could be as simple as using '\n' as a message seaparator, as long as '\n' is not part of your message payload (e.g. when unsign a simple text protocol).
You block the server for 5 seconds and it cannot receive some messages from the client.
for (int i = 0;; i++)
{
sleep(5);
valread = read(new_socket, buffer, 1024);
printf("%s\n", buffer);
}
How can a client check if the server is receiving a message? I think this was discussed in Linux socket: How to make send() wait for recv()
P.S. It looks like there is a synchronizing piece of code, but you pulled it out of the loop.
Server:
}
send(new_socket, hello, strlen(hello), 0);
Client:
}
valread = read(sock, buffer, 1024);

Socket reading and writing not in order

I'm trying to make a simple server program that waits for 2 clients to connect, sends the first client "1" and the second "2" to tell them who is first. then i want this kind of behavior:
client 1: writes
client 2: receives and prints
client 2: writes
client 1: receives and prints
What i'm getting is a weird behavior:
client 1: writes
client 2: writes and only then gets what client 1 wrote
client 1: writes and only then gets what client 1 wrote
and it keeps going.
CLIENT
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <netdb.h>
#include <iostream>
#include <unistd.h>
using namespace std;
int main() {
int clientSocket,first,readValue = 1;
char buffer[1024];
struct sockaddr_in serverAddr;
struct in_addr address;
struct hostent *server;
clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if(!inet_aton("127.0.0.1", &address)){
throw "Can't parse IP address";
}
server = gethostbyaddr((const void*)&address, sizeof address, AF_INET);
if(server == NULL){
throw "Host is unreachable";
}
serverAddr.sin_family = AF_INET;
memcpy((char*)&serverAddr.sin_addr.s_addr,
(char*)server->h_addr, server->h_length);
serverAddr.sin_port = htons(8000);
if(connect(clientSocket, (struct sockaddr *) &serverAddr,
sizeof serverAddr)){
throw "error connecting server";
}
cout<< "connected to server";
//Server tells the client if he's first or second
memset(&buffer[0], 0, sizeof(buffer));
read(clientSocket, buffer, sizeof buffer - 1);
//assigning the "first" variable
if(!strcmp(buffer,"1")){
first = 1;
cout<<"I am first";
}
else if(!strcmp(buffer,"2")){
first = 0;
cout<<"I am first";
}
else{
cout<<"Error";
return 0;
}
while (true)
{
memset(&buffer[0], 0, sizeof(buffer));
if(first == 0){
//read from server
readValue = read(clientSocket, buffer, sizeof buffer);
if(readValue < 1){
throw "Error reading from socket";
}
cout<<buffer<<endl;
//print it
memset(&buffer[0], 0, sizeof(buffer));
//write to buffer
cin>>buffer;
write(clientSocket,buffer,sizeof buffer);
memset(&buffer[0], 0, sizeof(buffer));
}
if(first == 1){
//write to buffer
cin>>buffer;
write(clientSocket,buffer,sizeof buffer);
memset(&buffer[0], 0, sizeof(buffer));
//read from server
readValue = read(clientSocket, buffer, sizeof buffer);
if(readValue < 1){
throw "Error reading from socket";
}
cout<<buffer<<endl;
}
}
return 0;
}
SERVER
void GameServer::start(){
int client1_sd, client2_sd;
char buffer[1024];
//clients' variables
struct sockaddr_in client1Address, client2Address;
socklen_t client1AddressLen, client2AddressLen;
//cleaning buffer
memset(&buffer[0], 0, sizeof(buffer));
//Creating the socket
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if(serverSocket == -1){
throw "Error opening socket";
}
//Creating socket address variable for binding
struct sockaddr_in serverAddress;
//initializing it to 0's
bzero((void *)&serverAddress, sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
//Gets connections from anything
serverAddress.sin_addr.s_addr= INADDR_ANY;
serverAddress.sin_port = htons(port);
//binding
if (bind(serverSocket, (struct sockaddr* )&serverAddress,
sizeof(serverAddress)) == -1){
throw "Error on binding";
}
listen(serverSocket, MAX_CONNECTED_CLIENTS);
//If a game has ended, start a new one
while(true){
//start listening for clients
cout<<"Waiting for connections"<<endl;
//Accepting first client
client1_sd = accept(serverSocket,
(struct sockaddr* )&client1Address,
&client1AddressLen);
cout<< "Client 1 entered!"<<endl;
//Sending 1 to him to show him he is the first to enter
buffer[0] = '1';
write(client1_sd,buffer,1024);
//Accepting second client
client2_sd = accept(serverSocket,
(struct sockaddr* )&client1Address,
&client1AddressLen);
cout<<"Client 2 entered!"<<endl;
//Sending 2 to him to show him he is the second to enter
buffer[0] = '2';
write(client2_sd,buffer,1024);
while(true){
memset(&buffer[0], 0, sizeof(buffer));
//taking input form client 1
read(client1_sd, buffer, 1024);
if(!strcmp(buffer, "End")){
close(client1_sd);
close(client2_sd);
break;
}
cout<<buffer<<endl;
//returning the message
write(client2_sd, buffer, 1024);
memset(&buffer[0], 0, sizeof(buffer));
//taking input from client 2
read(client2_sd, buffer, 1024);
if(strcmp(buffer, "End") == 0){
close(client1_sd);
close(client2_sd);
break;
}
cout<<buffer<<endl;
//returning the message
write(client1_sd, buffer, 1024);
}
}
}
While it's true what user4581301 wrote in his comment, your program behaves not as wanted even when write and read data are not fragmented, because:
the server sends "1" and "2" with write(clienti_sd,buffer,1024), i. e. it sends 1024 bytes;
each client receives its number with read(clientSocket, buffer, sizeof buffer - 1), i. e., since it's char buffer[1024], it can receive only 1023 bytes;
so, there remains 1 byte unread for the client, which the second client then receives with his next read from server, mistaking it for the data which would be sent after the server received from the first client, and thus the second client continues with writing early.

Send HTTP2 frame to server over TLS

I am trying to learn how the HTTP2 protocol works. I see that Apple uses it for their push notification server. I am using the specification for the frame from Discover HTTP.
As a test, I wrote code that is supposed to communicate with that server. However, I keep getting the error that I'm missing the "Settings" frame.
My code is as follows:
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <dlfcn.h>
#include <unistd.h>
#include <openssl/ssl.h>
#define SOCKET_ERROR -1
struct Frame //Represents and HTTP2 Frame.
{
char len[24];
char type[8];
char flags[8];
char identifier[31];
char payload[];
} __attribute__((packed));
void writeFrame(SSL* ssl)
{
//First thing after connecting is to send the PREFACE.
std::string preface = "PRI * HTTP/2.0\r\n\r\n";
preface += "SM\r\n\r\n";
SSL_write(ssl, preface.c_str(), preface.length());
//Now to send the first frame. Aka the SETTINGS frame.
Frame* frame = (Frame *)malloc(sizeof(Frame));
memset(frame, 0, sizeof(Frame));
int frameSize = 100;
memcpy(frame->len, &frameSize, sizeof(frameSize));
memcpy(frame->type, "SETTINGS", strlen("SETTINGS"));
memcpy(frame->identifier, "SETTINGS", strlen("SETTINGS"));
SSL_write(ssl, frame, sizeof(Frame));
//Read server response.
char buffer[10000];
memset(buffer, 0, sizeof(buffer));
int dataLen;
while ((dataLen = SSL_read(ssl, buffer, sizeof(buffer)) > 0))
{
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
std::cout << buffer[i];
i += 1;
}
}
//The above gives me the error:
//First received frame was not SETTINGS.
//Hex dump for first 5 bytes: 6400000000
//Try to POST to the server now.
std::string payload = "POST /3/device HTTP/2.0\r\n";
payload += ":method:POST\r\n";
payload += ":scheme: https\r\n";
payload += "cache-control: no-cache\r\n";
payload += "user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36\r\n";
payload += "content-type: text/plain;charset=UTF-8\r\n\r\n";
int sentBytes = SSL_write(ssl, payload.c_str(), payload.length());
if (sentBytes < payload.length() || sentBytes == SOCKET_ERROR)
{
return;
}
memset(buffer, 0, sizeof(buffer));
while ((dataLen = SSL_read(ssl, buffer, sizeof(buffer)) > 0))
{
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
std::cout << buffer[i];
i += 1;
}
}
}
int main(int argc, const char * argv[]) {
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
std::string address = "api.development.push.apple.com";
struct addrinfo hints = {0};
struct addrinfo* result = nullptr;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
getaddrinfo(address.c_str(), nullptr, &hints, &result);
int sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (sock == -1)
{
return -1;
}
struct sockaddr_in sockAddr;
sockAddr.sin_addr = reinterpret_cast<struct sockaddr_in*>(result->ai_addr)->sin_addr;
sockAddr.sin_family = result->ai_family;
sockAddr.sin_port = htons(443);
freeaddrinfo(result);
if (connect(sock, reinterpret_cast<sockaddr *>(&sockAddr), sizeof(sockAddr)) == SOCKET_ERROR)
{
close(sock);
return -1;
}
SSL_CTX* ctx = SSL_CTX_new(TLSv1_2_method());
SSL* ssl = SSL_new(ctx);
SSL_set_fd(ssl, sock);
SSL_connect(ssl);
writeFrame(ssl);
SSL_CTX_free(ctx);
SSL_shutdown(ssl);
SSL_free(ssl);
close(sock);
return 0;
}
How can I send the SETTINGS frame and other frames to the server? What have I missed?
You have several errors.
First of all, the Frame data structure, where the lengths of the array fields are wrong.
You seem to have copied their length in bits, but reported them in the Frame data structure in bytes.
You want this instead:
struct Frame {
char len[3];
char type;
char flags;
char identifier[4];
char payload[];
}
Furthermore, the type of the frame is not a string, nor is the identifier.
Finally, the format of the request is completely wrong, resembling HTTP/1.1, while the HTTP/2 format is completely different and based on HPACK.
I suggest you have a careful read of the HTTP/2 specification before writing further code.

C++ Winsock Sending file [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
a Simple Server and Client that I can send the file,
And I need you guys to see if this source are done.
Cuz I think it won't download the full file.
And maybe to this source have a limit ? Cuz I uploaded/downloaded 200K and a little bit more ..
Server:
#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")
SOCKET Socket, Sub;
WSADATA Winsock;
sockaddr_in Addr;
int Addrlen = sizeof(sockaddr_in);
char Buffer[256];
char *Str;
sockaddr_in IncomingAddress;
int AddressLen = sizeof(IncomingAddress);
int main()
{
WSAStartup(MAKEWORD(2, 2), &Winsock); // Start Winsock
if(LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2) // Check version
{
WSACleanup();
return 0;
}
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ZeroMemory(&Addr, sizeof(Addr));
Addr.sin_family = AF_INET;
Addr.sin_port = htons(6091);
bind(Socket, (sockaddr*)&Addr, sizeof(Addr));
if(listen(Socket, 1) == SOCKET_ERROR)
{
printf("listening error\n");
}
else
{
printf("listening ok\n");
}
if(Sub = accept(Socket, (sockaddr*)&IncomingAddress, &AddressLen))
{
char *ClientIP = inet_ntoa(IncomingAddress.sin_addr);
int ClientPort = ntohs(IncomingAddress.sin_port);
printf("Client conncted!\n");
printf("IP: %s:%d\n", ClientIP, ClientPort);
printf("Sending file .. \n");
FILE *File;
char *Buffer;
unsigned long Size;
File = fopen("C:\\Prog.exe", "rb");
if(!File)
{
printf("Error while readaing the file\n");
goto End;
}
fseek(File, 0, SEEK_END);
Size = ftell(File);
fseek(File, 0, SEEK_SET);
Buffer = new char[Size];
fread(Buffer, Size, 1, File);
char cSize[MAX_PATH];
sprintf(cSize, "%i", Size);
fclose(File);
send(Sub, cSize, MAX_PATH, 0); // File size
send(Sub, Buffer, Size, 0); // File Binary
free(Buffer);
End:
closesocket(Sub);
closesocket(Socket);
WSACleanup();
}
getchar();
return 0;
}
Client:
#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")
SOCKET Socket;
WSADATA Winsock;
sockaddr_in Addr;
int Addrlen = sizeof(Addr);
int main()
{
WSAStartup(MAKEWORD(2, 2), &Winsock); // Start Winsock
if(LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2) // Check version
{
WSACleanup();
return 0;
}
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ZeroMemory(&Addr, sizeof(Addr)); // clear the struct
Addr.sin_family = AF_INET; // set the address family
Addr.sin_addr.s_addr = inet_addr("127.0.0.1");
Addr.sin_port = htons(6091); // set the port
if(connect(Socket, (sockaddr*)&Addr, sizeof(Addr)) < 0)
{
printf("Connection failed !\n");
getchar();
return 0;
}
printf("Connection successful !\n");
printf("Receiving file .. \n");
int Size;
char *Filesize = new char[1024];
if(recv(Socket, Filesize, 1024, 0)) // File size
{
Size = atoi((const char*)Filesize);
printf("File size: %d\n", Size);
}
char *Buffer = new char[Size];
if(recv(Socket, Buffer, Size, 0)) // File Binary
{
FILE *File;
File = fopen("Prog.exe", "wb");
fwrite((const char*)Buffer, 1, Size, File);
fclose(File);
}
getchar();
closesocket(Socket);
WSACleanup();
return 0;
}
Thanks.
Your code may fail if you try to send/receive large amount of data. From the documentation of the send function:
Return value
If no error occurs, send returns the total number of
bytes sent, which can be less than the number requested to be sent in
the len parameter. Otherwise, a value of SOCKET_ERROR is returned, and
a specific error code can be retrieved by calling WSAGetLastError.
You have to check the return value of send(), and if it is less than the number of bytes requested to be sent, call send() again for the remaining data. Example:
char *data = Buffer; // data to be sent
int len = Size; // number of bytes to be sent
while (len > 0) {
int amount = send(Sub, data, len, 0);
if (amount == SOCKET_ERRROR) {
// handle error ...
} else {
len -= amount;
data += amount;
}
}
The same is true for the recv() call in the client.
This is the file send function which will read the file as binary and will send the data. This is an independent function just pass the value of the socket on which v need to send the data along with the file path which we need to send.
void FileSend(SOCKET FileSendSocket,char *FilePath)
{
streampos filesize = 0;
ifstream in(FilePath,ios::binary);
ZeroMemory( &sendbuf, sendbuflen);
if(in.is_open())
{
while(1)
{
in.read(sendbuf,sendbuflen);
if(in.eof())
{
cout << "End of File sending from Client" << endl;
in.close();
break;
}
else
{
send(FileSendSocket,sendbuf,sendbuflen,0);
ZeroMemory( &sendbuf, sendbuflen);
}
}
}
}
And this is the receive function on the client side and it should be called just next to the receive function this function will continuously write what ever data the server is sending.
ofstream out("C:\\Prog.exe",ios::binary);
void FileReceive(char* recvbuf, int recvbuflen)
{
if(out.is_open())
{
out.write(recvbuf,recvbuflen);
ZeroMemory(&recvbuf,recvbuflen);
}
}

Read the whole file and send it via sockets

I made a server and client that should transfer files.
I tried to make it read the whole file and send it.
But now as I see it, I am having a problem.
Server should automatically send the file when the client is connected.
But the file is empty, and I don't know where the problem is
You can see that I'm trying to send .txt file. But I would like in the future send a big file, but not bigger than 1MB.)
Edit:
Picture here: http://img819.imageshack.us/img819/8259/aadi.jpg
Left side: The file that I tried to send.
Right side: The file I received
The Problem: The file that I received has been damaged, and I can't use it.
Server:
#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "Ws2_32.lib")
#define Port 6000
SOCKET Socket, Sub;
WSADATA Winsock;
sockaddr_in Addr;
sockaddr_in IncomingAddress;
int AddressLen = sizeof(IncomingAddress);
int main()
{
WSAStartup(MAKEWORD(2, 2), &Winsock); // Start Winsock
if(LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2) // Check version
{
WSACleanup();
return 0;
}
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ZeroMemory(&Addr, sizeof(Addr));
Addr.sin_family = AF_INET;
Addr.sin_port = htons(Port);
bind(Socket, (sockaddr*)&Addr, sizeof(Addr));
if(listen(Socket, 1) == SOCKET_ERROR)
{
printf("listening error\n");
}
else
{
printf("listening ok\n");
}
if(Sub = accept(Socket, (sockaddr*)&IncomingAddress, &AddressLen))
{
char *ClientIP = inet_ntoa(IncomingAddress.sin_addr);
int ClientPort = ntohs(IncomingAddress.sin_port);
printf("Client conncted!\n");
printf("IP: %s:%d\n", ClientIP, ClientPort);
printf("Sending file .. \n");
FILE *File;
char *Buffer;
unsigned long Size;
File = fopen("C:\\Prog.rar", "rb");
if(!File)
{
printf("Error while readaing the file\n");
getchar();
return 0;
}
fseek(File, 0, SEEK_END);
Size = ftell(File);
fseek(File, 0, SEEK_SET);
Buffer = new char[Size];
fread(Buffer, Size, 1, File);
char cSize[MAX_PATH];
sprintf(cSize, "%i", Size);
fclose(File);
send(Sub, cSize, MAX_PATH, 0); // File size
//int len = Size;
//char *data = Buffer;
int Offset = 0;
while(Size > Offset)
{
int Amount = send(Sub, Buffer + Offset, Size - Offset, 0);
if(Amount <= 0)
{
cout << "Error: " << WSAGetLastError() << endl;
break;
}
else
{
Offset += Amount;
printf("2\n");
}
}
free(Buffer);
closesocket(Sub);
closesocket(Socket);
WSACleanup();
}
getchar();
return 0;
}
Client:
#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "Ws2_32.lib")
SOCKET Socket;
WSADATA Winsock;
sockaddr_in Addr;
int Addrlen = sizeof(Addr);
int main()
{
WSAStartup(MAKEWORD(2, 2), &Winsock); // Start Winsock
if(LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2) // Check version
{
WSACleanup();
return 0;
}
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ZeroMemory(&Addr, sizeof(Addr)); // clear the struct
Addr.sin_family = AF_INET; // set the address family
Addr.sin_addr.s_addr = inet_addr("127.0.0.1");
Addr.sin_port = htons(6000); // set the port
if(connect(Socket, (sockaddr*)&Addr, sizeof(Addr)) < 0)
{
printf("Connection failed !\n");
getchar();
return 0;
}
printf("Connection successful !\n");
printf("Receiving file .. \n");
int Size;
char *Filesize = new char[1024];
if(recv(Socket, Filesize, 1024, 0)) // File size
{
Size = atoi((const char*)Filesize);
printf("File size: %d\n", Size);
}
char *Buffer = new char[Size];
//int len = Size;
//char *data = Buffer;
int Offset = 0;
while(Size > Offset)
{
int Amount = recv(Socket, Buffer + Offset, Size - Offset, 0);
if(Amount <= 0)
{
cout << "Error: " << WSAGetLastError() << endl;
break;
}
else
{
Offset += Amount;
printf("2\n");
}
}
FILE *File;
File = fopen("Prog.rar", "wb");
fwrite(Buffer, 1, Size, File);
fclose(File);
getchar();
closesocket(Socket);
WSACleanup();
return 0;
}
The send API may not send all the data you requested to send. So, you have to pay attention to the return value, and retry the send from where the last send ended. As an example:
offset = 0;
while (offset < bufsize) {
r = send(socket, buf+offset, bufsize-offset);
if (r <= 0) break;
offset += r;
}
While you are doing something similar for your file transfer, you do not make sure this is the case for your file size.
When you send the file size, you only need to send the string that represents the size, not the entire MAX_PATH. The receiver then needs to parse the first string to determine the size, but any data read in after the end of the first string needs to be considered part of the file. However, since you are trying the send MAX_PATH, the receiver should receive the same amount. Your client code receives 1024 bytes, but there is no indication this is the same size as MAX_PATH.
The recv API may also return fewer bytes than requested. You use a loop to handle reading the file, but you may need a loop to read the entire message that contains the file size.
In your client receive loop, you are incrementing the data pointer. This makes it unusable to write out the file later. You already have Buffer though, so use that to write out your file.
fwrite(Buffer, 1, len, File);
If you encounter an error doing socket I/O, you can retrieve the error with WSAGetLastError(), or you can issue getsockopt() on the socket with the SO_ERROR option. These may return different values, but the error reason should be correlated.
Myself faced the same problem and after googling found that send() api can send a maximum data based on low level TCP buffers which are os dependent.So inorder to send a huge file we need to perform file chunking , ie send the file in the form of chunks.
`const int FILE_CHUNK_SIZE = 2000;
//get file size
ifstream file("myFile.file", ios::binary);
file.seekg(0, ios::end);
unsigned int fileSize = file.tellg();
file.close();
//get the file
char* fileBuffer = new char[fileSize];
file.open("myFile.file", ios::binary);
file.seekg (0, ios::beg);
file.read (fileBuffer, fileSize);
file.close();
//send file in chunks
unsigned int bytesSent = 0;
int bytesToSend = 0;
while(bytesSent < fileSize)
{
if(fileSize - bytesSent >= FILE_CHUNK_SIZE)
bytesToSend = FILE_CHUNK_SIZE;
else
bytesToSend = fileSize - bytesSent;
send(ConnectSocket, fileBuffer + bytesSent, bytesToSend, 0 );
bytesSent += bytesToSend;
}
delete [] fileBuffer;`
At the receiving end we need to have a recv() api called till the whole file content is read.
credits to:shacktar cplusplus.com