sending and recieving file from tcp socket. Sending the file works however trying to save the file does not work.
#include <cassert>
#include <arpa/inet.h>
#include <cstdlib>
#include <iostream>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <fstream>
#include <time.h>
#include <strings.h>
#include <sstream>
#include <vector>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/sendfile.h>
#include <fcntl.h>
using namespace std;
using std::endl;
int newscount = 0;
int doccount = 0;
int photocount = 0;
int johns = 0;
vector<string> newsvector;
vector<string> photosvector;
vector<string> docsvector;
void serverlogs(const char*msg) /* writing to log file */
{
time_t rawtime;
struct tm * timeinfo;
time (&rawtime);
timeinfo = localtime(&rawtime);
ofstream file;
file.open("serverlog.txt",ios::app);
if (file.is_open())
{file<<msg;
file<<" # ";
file<<asctime(timeinfo);
file<<"\n";
file.close();
return;
}
else
cout<<"Error Creating log file";
return;
}
void clientlogs(const char*msg) /* writing to log file */
{
time_t rawtime;
struct tm * timeinfo;
time (&rawtime);
timeinfo = localtime(&rawtime);
ofstream file;
file.open("clientlog.txt",ios::app);
if (file.is_open())
{file<<msg;
file<<" # ";
file<<asctime(timeinfo);
file<<"\n";
file.close();
return;
}
else
cout<<"Error Creating log file";
return;
}
void error(const char*msg) /* If there is an error exit the program with err# 1 */
{
perror(msg);
exit(1);
}
void publishdocsvector(const char*msg)
{
docsvector.push_back(msg);
ofstream file;
file.open("docfiles.txt",ios::app);
if (file.is_open())
{
for(int j = 0; j < docsvector.size() ;j++)
{file<<docsvector[j];}
file.close();
}
else
cout<<"Error creating news archive";
return;
}
void publishphotosvector(const char*msg)
{
photosvector.push_back(msg);
ofstream file;
file.open("photofiles.txt",ios::app);
if (file.is_open())
{
for(int j = 0; j < photosvector.size() ;j++)
{file<<photosvector[j];}
file.close();
}
else
cout<<"Error creating news archive";
return;
}
void publishnewsvector(const char*msg)
{
newsvector.push_back(msg);
ofstream file;
file.open("newsfiles.txt",ios::app);
if (file.is_open())
{
for(int j = 0; j < newsvector.size() ;j++)
{file<<newsvector[j];}
file.close();
}
else
cout<<"Error creating news archive";
return;
}
void sendfile(const char*msg)
{
// to be implemented later//
}
int main (int argc, char*argv[]) /*Main Program accepting a port number and something else for arguments */
{
int sockfd, newsockfd, portno, clilen, n,test;
string publish="publish";
string search= "search";
string get="get";
string newsstring = "news";
string docstring = "doc";
string photostring = "photo";
string wrap = "exit";
char buffer[256];
char seats [50];
serverlogs("Server Running");
struct sockaddr_in serv_addr, cli_addr; /* Defines the server address and client address and types of structures with the same format as socket address */
if (argc < 2)
{
fprintf(stderr,"Please provide a port number next time plz, goodbye!");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0); /* If Sock_Dgram then then it will open a udp socket */
if (sockfd < 0)
error("Error opening socket");
bzero((char *)&serv_addr, sizeof(serv_addr)); /* sets the server address to zero usings its reference */
portno = atoi(argv[1]); /*2nd argument vector is the port number and converted into an integer, the first [0] is the running program */
serv_addr.sin_family = AF_INET; /* The structure sockaddr_in has four fields, this is first one and should always be this */
serv_addr.sin_port = htons(portno); /* convert port number into network byte order */
serv_addr.sin_addr.s_addr = INADDR_ANY; /*3rd Field uses Ip address of host machine */
if (bind(sockfd,(struct sockaddr *) &serv_addr, sizeof(serv_addr))<0) /*bind socket to sockfd and address of server ,and needs size of address need struct of sockaddr, see bind man for details*/
error("Couldn't bind socket to address");
listen(sockfd,5);
clilen = sizeof(cli_addr);
serverlogs("going into server loop");
int pid = fork();
if (pid < 0)
serverlogs("error on initial separtion of server and client");
if (pid==0)
{
// server loop later on this will be the child process and client will be main
while (1)
{ /* Server loop loop*/
newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr, (socklen_t*)&clilen);
if (newsockfd < 0)
/* error("Corrupt log"); */
serverlogs("Connection not accepted");
else (newsockfd > 0);
int ppID = fork();
if (ppID < 0)
serverlogs("A new server process failed to be created");
if (ppID == 0)
{
int uid;
uid = johns;
printf("A new client connected with identity: %d\n", getpid());
close(sockfd);
serverlogs("A john Connected to the server");
printf("my unique id: %d\n", uid);
serverlogs(seats);
bzero(buffer,256);
//n = write(newsockfd,"Each client is a 'john' \n",26);
/* This loop read from socket and writes to other persons sockets */
while(1)
{
bzero(buffer,256);
n = read(newsockfd,buffer,256);
if (n < 0)
printf ("error reading from socket here is the message: %s",buffer);
if (publish[0] == buffer[0])
{
n = write(newsockfd,"What category are you publishing in?(news,photos,documents) \n",62);
bzero(buffer,256);
n = read(newsockfd,buffer,256);
if(buffer[0]==newsstring[0])
{
n = write(newsockfd,"Type the name of the file to publish and wait 10 seconds \n",59);
bzero(buffer,256);
n = read(newsockfd,buffer,256);
publishnewsvector(buffer);
serverlogs(seats);
serverlogs("client is trying to publish a news file:");
serverlogs(buffer);
/*start recieving a file*/
std::ofstream file;
file.open(buffer, std::ios::out | std::ios::binary);
assert(file.is_open());
while (1) {
std::cout << "..";
bzero(buffer,256);
n = read(newsockfd, buffer, sizeof(buffer));
assert(n != -1);
if (n == 0)
break;
file.write(buffer, n);
i++;
}
file.close();
serverlogs("File Transfered successfully");
}
if(buffer[0]==docstring[0])
{
n = write(newsockfd,"Type the name of the file to publish \n",39);
bzero(buffer,256);
n = read(newsockfd,buffer,256);
publishdocsvector(buffer);
serverlogs(seats);
serverlogs("client is tyring to publish a document:" );
serverlogs(buffer);
/*start recieving a file*/
std::ofstream file;
file.open(buffer, std::ios::out | std::ios::binary);
assert(file.is_open());
while (1) {
std::cout << ".";
bzero(buffer,256);
n = read(newsockfd, buffer, sizeof(buffer));
assert(n != -1);
if (n == 0)
break;
file.write(buffer, n);
}
file.close();
serverlogs("File Transfered successfully");
}
if(buffer[0]==photostring[0])
{
n = write(newsockfd,"Type the name of the file to publish \n",39);
bzero(buffer,256);
n = read(newsockfd,buffer,256);
publishphotosvector(buffer);
serverlogs(seats);
serverlogs("client is trying to publish photo file:" );
serverlogs(buffer);
/*start recieving a file*/
std::ofstream file;
file.open(buffer, std::ios::out | std::ios::binary);
assert(file.is_open());
while (1) {
std::cout << ".";
bzero(buffer,256);
n = read(newsockfd, buffer, sizeof(buffer));
assert(n != -1);
if (n == 0)
break;
file.write(buffer, n);
}
file.close();
serverlogs("File Transfered successfully");
}
}
if (get[0] ==buffer[0])
{
n = write(newsockfd,"\n What file do you want to get? \n",35);
bzero(buffer,256);
n = read(newsockfd,buffer,256);
serverlogs(seats);
serverlogs("client wants file:");
serverlogs(buffer);
//** start sending the file**//
FILE* searchfile = 0;
long Size = 0;
searchfile = fopen(buffer,"r");
fseek(searchfile, 0, SEEK_END);
Size = ftell(searchfile);
char *bufferfile = (char*)malloc(Size);
memset(bufferfile, 0, Size);
fseek(searchfile, 0, SEEK_SET);
fread(bufferfile, Size, 1, searchfile);
n = write(newsockfd,bufferfile,256);
fclose(searchfile);
serverlogs("Sent the file to the client");
serverlogs(seats);
}
if (search[0] == buffer[0])
{
bzero(buffer,256);
n = write(newsockfd,"What category are you searching? \n",35);
bzero(buffer,256);
n = read(newsockfd,buffer,256);
serverlogs(seats);
serverlogs("client searching for");
serverlogs(buffer);
if(buffer[0]==newsstring[0])
{
FILE* searchfile = 0;
long Size = 0;
searchfile = fopen("newsfiles.txt","r");
fseek(searchfile, 0, SEEK_END);
Size = ftell(searchfile);
char *bufferfile = (char*)malloc(Size);
memset(bufferfile, 0, Size);
fseek(searchfile, 0, SEEK_SET);
fread(bufferfile, Size, 1, searchfile);
n = write(newsockfd,bufferfile,256);
fclose(searchfile);
}
if(buffer[0]==docstring[0])
{
FILE* searchfile = 0;
long Size = 0;
searchfile = fopen("docfiles.txt","r");
fseek(searchfile, 0, SEEK_END);
Size = ftell(searchfile);
char *bufferfile = (char*)malloc(Size);
memset(bufferfile, 0, Size);
fseek(searchfile, 0, SEEK_SET);
fread(bufferfile, Size, 1, searchfile);
n = write(newsockfd,bufferfile,256);
fclose(searchfile);
}
if(buffer[0]==photostring[0])
{
FILE* searchfile = 0;
long Size = 0;
searchfile = fopen("photofiles.txt","r");
fseek(searchfile, 0, SEEK_END);
Size = ftell(searchfile);
char *bufferfile = (char*)malloc(Size);
memset(bufferfile, 0, Size);
fseek(searchfile, 0, SEEK_SET);
fread(bufferfile, Size, 1, searchfile);
n = write(newsockfd,bufferfile,256);
fclose(searchfile);
}
}
if(buffer[0]==wrap[0])
{
close(sockfd);
close(newsockfd);
johns = johns - 1;
serverlogs("A john left");
return 0;
}
n = write(newsockfd,"\n Waiting for a command I can understand:(publish,search,get,exit)",66);
} /* while loop to listen to commands from client bracket */
}/*what to do when client connected*/
} /*Creating child/zombies */
} /* division between client and server*/
else
{
while (1)
{int ssockfd, pportno, p,peer;
struct sockaddr_in peer_addr;
struct hostent *peerserver;
char bbuffer[256];
printf ("%s \n", "Welcome to the Social");
printf ("%s \n", "Please type the port number of the server \n");
cin>>pportno;
ssockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket Please try again");
printf ("%s \n", "Please type in the hostname of client ie sunlab1.njit.edu \n");
char peers[256];
cin >> peers;
peerserver = gethostbyname(peers);
if (peerserver == NULL)
{
fprintf(stderr,"could not connect to ip address");
peerserver = gethostbyname((const char*)peer);
if (peerserver == NULL)
fprintf(stderr,"still null");
exit(0);
}
bzero((char *) &peer_addr, sizeof(peer_addr));
peer_addr.sin_family = AF_INET;
bcopy((char *)peerserver->h_addr,(char *)&peer_addr.sin_addr.s_addr,peerserver->h_length);
peer_addr.sin_port = htons(pportno);
if (connect(ssockfd,(struct sockaddr *)&peer_addr,sizeof(peer_addr)) < 0)
error("ERROR connecting");
clientlogs("Connected to peer");
clientlogs((const char*)&peer);
printf("Please enter a command, publish,search or get: ");
while (1)
{
bzero(bbuffer,256);
fgets(bbuffer,255,stdin);
char apub[] = "publish";
char asearch[] = "search";
char aget[]="get";
if (bbuffer[0]==apub[0] && bbuffer[1]==apub[1])
{
p = write(ssockfd,bbuffer,strlen(bbuffer));
if (p < 0)
error("ERROR writing to socket");
bzero(bbuffer,256);
p = read(ssockfd,bbuffer,255);
if (p < 0)
error("ERROR reading from socket");
printf("%s",bbuffer); //What category are you publishing in//
bzero(bbuffer,256);
fgets(bbuffer,255,stdin);
p = write(ssockfd,bbuffer,strlen(bbuffer));
clientlogs("Client publishing");
clientlogs(bbuffer);
if (p < 0)
error("ERROR writing to socket");
bzero(bbuffer,256);
p = read(ssockfd,bbuffer,255);
if (p < 0)
error("ERROR reading from socket");
printf("%s",bbuffer); //Type the name of the file//
fgets(bbuffer,255,stdin);
p = write(ssockfd,bbuffer,strlen(bbuffer));
clientlogs(bbuffer);
FILE* searchfile = 0;
long Size = 0;
searchfile = fopen(bbuffer,"r");
fseek(searchfile, 0, SEEK_END);
Size = ftell(searchfile);
char *bufferfile = (char*)malloc(Size);
memset(bufferfile, 0, Size);
fseek(searchfile, 0, SEEK_SET);
fread(bufferfile, Size, 1, searchfile);
p = write(ssockfd,bufferfile,256);
fclose(searchfile);
}
if(bbuffer[0]==aget[0] && bbuffer[1]==aget[1])
{
p = write(ssockfd,bbuffer,strlen(bbuffer));
if (p < 0)
error("ERROR writing to socket");
bzero(bbuffer,256);
p = read(ssockfd,bbuffer,255);
if (p < 0)
error("ERROR reading from socket");
printf("%s",bbuffer); //What file do you want to get? //
bzero(bbuffer,256);
fgets(bbuffer,255,stdin);
p = write(ssockfd,bbuffer,strlen(bbuffer));
if (p < 0)
error("ERROR writing to socket");
clientlogs("client wants file:");
clientlogs(bbuffer);
/*start recieving a file*/
std::ofstream file;
file.open(bbuffer, std::ios::out | std::ios::binary);
assert(file.is_open());
char buffer[255];
while (1) {
std::cout << ".";
bzero(bbuffer,256);
p = read(ssockfd, bbuffer, sizeof(bbuffer));
assert(p != -1);
if (p == 0)
break;
file.write(bbuffer, p);
}
file.close();
serverlogs("File Transfered successfully");
}
if (bbuffer[0]==asearch[0] && bbuffer[1]==asearch[1])
{
p = write(ssockfd,bbuffer,strlen(bbuffer));
if (p < 0)
error("ERROR writing to socket");
bzero(bbuffer,256);
p = read(ssockfd,bbuffer,255);
if (p < 0)
error("ERROR reading from socket");
printf("%s",bbuffer); // what category? //
fgets(bbuffer,255,stdin);
p = write(ssockfd,bbuffer,strlen(bbuffer));
if (p < 0)
error("ERROR writing to socket");
clientlogs("Client searching for file");
clientlogs(bbuffer);
bzero(bbuffer,256);
p = read(ssockfd,bbuffer,255);
if (p < 0)
error("ERROR reading from socket");
printf("%s",bbuffer); //The vector array of the files //
}
if (bbuffer[0]==wrap[0] && bbuffer[1]==wrap[1])
{ p = write(ssockfd,bbuffer,strlen(bbuffer));
exit(0); }
}//end of client loop asking to enter a command
}
}
return 0;
}
The problem I see is file << bbuffer. The ofstream's << operator writes until the first NULL byte. Don't forget your buffer is a string (or better, a char *). So, if bbuffer doesn't contain a NULL byte, your program is likely to crash with a SIGSEGV.
You should use file.write(bbuffer, p) instead of file << bbuffer. Also, there's no need to cleanup your buffer using bzero or memset.
And since you didn't provide a compilable source, I wrote the following (supposing Linux/Unix):
#include <cassert>
#include <iostream>
#include <fstream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main() {
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sa_dst;
memset(&sa_dst, 0, sizeof(struct sockaddr_in));
sa_dst.sin_family = AF_INET;
sa_dst.sin_port = htons(1234);
sa_dst.sin_addr.s_addr = inet_addr("127.0.0.1");
int ret = connect(fd, (struct sockaddr *)&sa_dst, sizeof(struct sockaddr));
assert(ret != -1);
std::ofstream file;
file.open("received.bin", std::ios::out | std::ios::binary);
assert(file.is_open());
char buffer[255];
while (1) {
std::cout << "..";
ssize_t p = read(fd, buffer, sizeof(buffer));
assert(p != -1);
if (p == 0)
break;
file.write(buffer, p);
}
file.close();
}
You can test it using netcat on your terminal:
$ nc -l 1234 < some_binary_file &
$ ./program
$ cmp some_binary_file received.bin
Related
I'm trying to implement transmission of files through UDP protocol in C++.
What I've got is the server which can send a file requested by a client, but it only works for .txt files. When I try to do the same with image or executable, the transmission corrupts and the file is about 0 KB.
Server:
#include <winsock2.h>
#include <stdio.h>
#include <iostream>
#include <sstream>
#pragma comment(lib, "ws2_32.lib")
#define cipherKey 'S'
int const bufferSize = 512;
char buffer[bufferSize];
void clearBuf(char* b)
{
int i;
for (i = 0; i < bufferSize; i++)
b[i] = '\0';
}
char* notFound = "File not found.";
char Cipher(char ch)
{
return ch ^ cipherKey;
}
int sendFile(FILE* file, char* buffer, int s)
{
int i, len;
if (file == NULL)
{
strcpy(buffer, notFound);
len = strlen(notFound);
buffer[len] = EOF;
return 1;
}
char ch, ch2;
for (i = 0; i < s; i++)
{
ch = fgetc(file);
ch2 = Cipher(ch);
buffer[i] = ch2;
if (ch == EOF)
return 1;
}
return 0;
}
int main()
{
WSADATA wsaData;
int wynik_winsock = WSAStartup(MAKEWORD(2,2), &wsaData);
if(wynik_winsock != 0)
{
exit(1);
}
SOCKET socketServer;
socketServer = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(socketServer == INVALID_SOCKET)
{
WSACleanup();
exit(1);
}
char* ipAdd = "127.0.0.1";
int port = 1234;
SOCKADDR_IN server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ipAdd);
if(bind(socketServer, (SOCKADDR *)&server, sizeof(server)) == SOCKET_ERROR)
{
closesocket(socketServer);
WSACleanup();
exit(1);
}
std::cout << "Waiting." << std::endl;
SOCKADDR_IN client;
int len_client = sizeof(client);
FILE* file;
if(recvfrom(socketServer, buffer, bufferSize, 0, (SOCKADDR *)&client, &len_client) == SOCKET_ERROR) //Odbiór danych od clienta wraz z kontrolą błędów.
{
closesocket(socketServer);
WSACleanup();
exit(1);
}
else
{
file = fopen(buffer, "rb");
std::cout << "Filename: " << buffer << std::endl;
if(file == NULL)
{
std::cout << "Couldnt open a file." << std::endl;
}
else
{
while (true)
{
if(sendFile(file, buffer, bufferSize))
{
sendto(socketServer, buffer, bufferSize, 0, (SOCKADDR *)&client, len_client);
break;
}
sendto(socketServer, buffer, bufferSize, 0, (SOCKADDR *)&client, len_client);
clearBuf(buffer);
}
fclose(file);
}
}
closesocket(socketServer);
WSACleanup();
system("pause");
return 0;
}
Client:
#include <winsock2.h>
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <string.h>
#pragma comment(lib, "ws2_32.lib")
#define cipherKey 'S'
int const bufferSize = 512;
char buffer[bufferSize];
void clearBuf(char* b)
{
int i;
for (i = 0; i < bufferSize; i++)
b[i] = '\0';
}
char Cipher(char ch)
{
return ch ^ cipherKey;
}
int recvFile(char* buffer, int s, FILE* file)
{
int i;
char ch;
for (i = 0; i < s; i++)
{
ch = buffer[i];
ch = Cipher(ch);
if (ch == EOF)
{
return 1;
}
else
{
fprintf(file, "%c", ch);
}
}
return 0;
}
int main()
{
WSADATA wsaData;
int wynik_winsock = WSAStartup(MAKEWORD(2,2), &wsaData);
if(wynik_winsock != 0)
{
exit(1);
}
SOCKET socketClient;
socketClient = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(socketClient == INVALID_SOCKET)
{
WSACleanup();
exit(1);
}
char* ipAdd = "127.0.0.1";
int port = 1234;
SOCKADDR_IN server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ipAdd);
int serverSizeOf = sizeof(server);
std::cout << "Name of file to send: ";
std::cin >> buffer;
if(sendto(socketClient, buffer, bufferSize, 0, (SOCKADDR *)&server, serverSizeOf) == SOCKET_ERROR)
{
closesocket(socketClient);
WSACleanup();
exit(1);
}
FILE* file;
file = fopen(buffer, "ab");
while (true)
{
clearBuf(buffer);
if(recvfrom(socketClient, buffer, bufferSize, 0, (SOCKADDR *)&server, &serverSizeOf) == SOCKET_ERROR)
{
closesocket(socketClient);
WSACleanup();
exit(1);
}
if (recvFile(buffer, bufferSize, file))
{
break;
}
fclose(file);
}
closesocket(socketClient);
WSACleanup();
system("pause");
return 0;
}
To do what I said above, I used the tutorial: C program for file Transfer using UDP (Linux).
How can I adapt the code to send other files than .txt only? Thank you in advance.
As said in the comments above you need a data type where EOF has a different value from all other character values, char is inadequate in this respect, especially when you are dealing with binary data.
The following change should improve things
int sendFile(FILE* file, char* buffer, int s)
{
...
for (i = 0; i < s; i++)
{
int ch = fgetc(file);
if (ch == EOF)
return 1;
buffer[i] = Cipher(ch);
}
...
I've decided to change nearly everything in the original solution I tried to implement. The most important changes are reading file using fread and writing it using fwrite.
The file is send in parts of 512 bytes (or less) and those parts are counted in the variable.
If the file requested by a client doesn't exist on the server, special information is sent and the file created to save data is deleted.
Now the program works as expected even for executables and SHA256 of both files, original and received, are the same.
Server:
//SERVER
#include <winsock2.h>
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <ctime>
#pragma comment(lib, "ws2_32.lib")
int main()
{
WSADATA wsaData;
int winsock_result = WSAStartup(MAKEWORD(2,2), &wsaData);
if(winsock_result != 0)
{
exit(1);
}
SOCKET server_socket;
server_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(server_socket == INVALID_SOCKET)
{
WSACleanup();
exit(1);
}
char* ip_address = "127.0.0.1";
int port = 6666;
SOCKADDR_IN server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ip_address);
if(bind(server_socket,(SOCKADDR *)&server, sizeof(server)) == SOCKET_ERROR)
{
closesocket(server_socket);
WSACleanup();
exit(1);
}
std::cout << "Waiting for data." << std::endl;
SOCKADDR_IN client;
int client_sizeof = sizeof(client);
int const buffer_size = 512;
char buffer[buffer_size];
if(recvfrom(server_socket, buffer, buffer_size, 0,(SOCKADDR *)&client, &client_sizeof) == SOCKET_ERROR)
{
closesocket(server_socket);
WSACleanup();
exit(1);
}
else
{
FILE* file;
file = fopen(buffer, "rb");
std::cout << "Filename: " << buffer << std::endl;
if(file == NULL)
{
std::cout << "Couldn't open the file." << std::endl;
strcpy(buffer, "NOFILE");
if(sendto(server_socket, buffer, buffer_size, 0,(SOCKADDR *)&client, client_sizeof) == SOCKET_ERROR)
{
fclose(file);
closesocket(server_socket);
WSACleanup();
exit(1);
}
}
fseek(file, 0, SEEK_END);
int file_size = ftell(file);
size_t reading_size;
int part = 0;
const clock_t begin_time = clock();
while((part * buffer_size) < file_size)
{
fseek(file, (part * buffer_size), SEEK_SET);
reading_size = fread(buffer, 1, buffer_size, file);
if(sendto(server_socket, buffer, reading_size, 0,(SOCKADDR *)&client, client_sizeof) == SOCKET_ERROR)
{
fclose(file);
closesocket(server_socket);
WSACleanup();
exit(1);
}
part++;
}
std::cout << "Sent " << part << " parts of " << buffer_size << " bytes." << std::endl;
std::cout << "Time of sending file: " << float( clock () - begin_time ) / CLOCKS_PER_SEC << " seconds." << std::endl;
strcpy(buffer, "QUIT");
if(sendto(server_socket, buffer, buffer_size, 0,(SOCKADDR *)&client, client_sizeof) == SOCKET_ERROR)
{
fclose(file);
closesocket(server_socket);
WSACleanup();
exit(1);
}
fclose(file);
}
closesocket(server_socket);
WSACleanup();
system("pause");
return 0;
}
Client:
//CLIENT
#include <winsock2.h>
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <string.h>
#pragma comment(lib, "ws2_32.lib")
int main()
{
WSADATA wsaData;
int winsock_result = WSAStartup(MAKEWORD(2,2), &wsaData);
if(winsock_result != 0)
{
exit(1);
}
SOCKET client_socket;
client_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(client_socket == INVALID_SOCKET)
{
WSACleanup();
exit(1);
}
char* ip_address = "127.0.0.1";
int port = 6666;
SOCKADDR_IN server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ip_address);
int server_sizeof = sizeof(server);
int const buffer_size = 512;
char buffer[buffer_size];
std::cout << "Name of the requested file: ";
std::cin >> buffer;
char filename[buffer_size];
strcpy(filename, buffer);
if(sendto(client_socket, buffer, buffer_size, 0,(SOCKADDR *)&server, server_sizeof) == SOCKET_ERROR)
{
closesocket(client_socket);
WSACleanup();
exit(1);
}
FILE* file;
file = fopen(filename, "wb");
int received_size = 0;
while(true)
{
received_size = recvfrom(client_socket, buffer, buffer_size, 0,(SOCKADDR *)&server, &server_sizeof);
if(received_size == SOCKET_ERROR)
{
fclose(file);
closesocket(client_socket);
WSACleanup();
exit(1);
}
if(strcmp(buffer, "NOFILE") == 0)
{
std::cout << "The file does not exist on the server." << std::endl;
fclose(file);
remove(filename);
break;
}
else if(strcmp(buffer, "QUIT") == 0)
{
std::cout << "Transmission ended by the server." << std::endl;
break;
}
fwrite(buffer, sizeof(char), received_size, file);
}
fclose(file);
closesocket(client_socket);
WSACleanup();
system("pause");
return 0;
}
I'm a newbie in socket programming. I'm trying to make a server/ client program to download a file.
Firstly, i init some step that i usually do in other program for set up a connection form client to server.
Next, From server side, I'm try to in put number of bytes that send to client to set up the receive buffer's size. From client side, I receive the number in string type. I convert it to long type and set it to buffer size.
Then, From client side, I enter the name of file that need to download from server. Server receive the name and check if it exist or not.
Last step ( THE PROBLEM STEP, i think ) server try to open file. if file is opened, send the file name back to client. client check file name if it same what it sent or not.
======> my problem is file name sent back to client:
- From server side: I print it out and check. it's correct.
- From client: I print buffer out right after read from server. It's not correct. sometimes, it's empty. sometimes, it's some-random-value.
I have done exactly like previous step.
Server.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2)
{
perror("you have to input port");
exit(1);
}
// init sockfd
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("sockfd perror");
exit(1);
}
// sockopt
int opt = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
// init server
bzero(&serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
// bind port
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
{
perror("ERROR on binding");
exit(1);
}
listen(sockfd, 5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (newsockfd < 0)
{
perror("ERROR on accept");
exit(1);
}
char buffer[256];
// write buff size
int buffsize;
printf("Input recive buffsize in Byte: ");
scanf("%d", &buffsize);
if (buffsize <= 0)
{
perror("Buffer size must be > 0");
exit(1);
}
bzero(buffer, sizeof(buffer));
bcopy(to_string(buffsize).c_str(), buffer, sizeof(buffer));
n = write(newsockfd, buffer, sizeof(buffer));
if (n < 0)
{
perror("fail to send buffer size");
exit(0);
}
//read file name
bzero(buffer, sizeof(buffer));
n = read(newsockfd, buffer, sizeof(buffer));
if (n < 0)
{
perror("ERROR reading from socket");
exit(1);
}
// open file:
char filename[strlen(buffer) + 1];
bcopy(buffer, filename, sizeof(filename));
FILE *pf;
unsigned long fsize;
pf = fopen(filename, "rb");
if (pf == NULL)
{
bzero(buffer, sizeof(buffer));
bcopy("File not found", buffer, sizeof(buffer));
n = write(newsockfd, buffer, sizeof(buffer));
if (n < 0)
{
perror("ERROR writing to socket");
exit(1);
}
printf("File not found!\n");
return 1;
}
else
{
printf("File %s is openned \n", filename);
fseek(pf, 0, SEEK_END);
fsize = ftell(pf);
rewind(pf);
printf("File has %ld bytes!\n", fsize);
}
// write OK response file name
bzero(buffer, sizeof(buffer));
bcopy(filename, buffer, sizeof(buffer));
printf("\n\n\n\n%s\n\n\n\n", buffer);
n = write(newsockfd, buffer, sizeof(buffer));
if (n < 0)
{
perror("ERROR writing to socket");
exit(1);
}
close(newsockfd);
close(sockfd);
return 0;
}
Client.cpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
if (argc < 3)
{
fprintf(stderr, "usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
// init sockfd
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("sockfd error");
exit(1);
}
// init server
server = gethostbyname(argv[1]);
if (server == NULL)
{
fprintf(stderr, "ERROR, no such host\n");
exit(0);
}
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
serv_addr.sin_port = htons(portno);
// connect
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
{
perror("ERROR connecting");
exit(1);
}
// recive and set buffer size:
char tempBuff[10];
bzero(tempBuff, 10);
n = read(sockfd, tempBuff, sizeof(tempBuff));
if (n < 0)
{
perror("fail to recive buffer size");
exit(1);
}
char buffer[stol(string(tempBuff))];
printf("Connect succes, Buffer size is %ld Bytes\n", sizeof(buffer));
// input file:
printf("Input file name to download: ");
string filename;
cin >> filename;
// Send filename
bzero(buffer, sizeof(buffer));
bcopy(filename.c_str(), buffer, filename.length());
n = write(sockfd, buffer, strlen(buffer));
if (n < 0)
{
perror("ERROR writing to socket");
}
// read file name response
bzero(buffer, sizeof(buffer));
n = read(sockfd, buffer, sizeof(buffer));
if (n < 0)
{
perror("ERROR reading from socket");
}
printf("\n\n\n\n%s, %ld\n\n\n\n", buffer, strlen(buffer));
// if (strcmp(buffer, filename.c_str()) == 0)
// {
// printf("OK!\n");
// }
// else
// {
// perror("Wrong filename");
// printf("server msg: %s\n", buffer);
// exit(1);
// }
close(sockfd);
return 0;
}
RUN CODE WITH FOLLOWING COMMAND:
Client: ./client [server ip] [port]
Server: ./server [port]
My result:
Update 1: problem disappear when i remove these line:
// write buff size
int buffsize;
printf("Input recive buffsize in Byte: ");
scanf("%d", &buffsize);
if (buffsize <= 0)
{
perror("Buffer size must be > 0");
exit(1);
}
at server.cpp
and these line:
// recive and set buffer size:
bzero(tempBuff, sizeof(tempBuff));
n = read(sockfd, tempBuff, sizeof(tempBuff));
if (n < 0)
{
perror("fail to recive buffer size");
exit(1);
}
// char buffer[stol(string(tempBuff))];
at client.cpp
I solved it. this problem occur due to tempBuff is too small. it's just 10 bytes. Using bigger tempBuff will solve the problem.
I am writing a tftp server in C and testing it with the tftp command on the terminal. However, for most of the times, I receive something liske the following when I try to send RRQ:
tftp> get a.txt
sent RRQ <file=a.txt, mode=netascii>
received ERROR <code=4, msg=>
Error code 1024:
other barly happend case includes:
tftp> get a.txt
sent RRQ <file=a.txt, mode=netascii>
received DATA <block=20334, 512 bytes>
discarded 4 packets
and this one: this might look correct but it barely happened. The text file I use to test it is of 857 bytes.
sent ACK <block=1>
received DATA <block=1, 512 bytes>
sent ACK <block=1>
received DATA <block=2, 345 bytes>
Received 857 bytes in 0.0 seconds
and here is part of my code
Here buffer is a char array of size 512 , to simplify the code, I have removed some of the error handling code
Thanks to whoever may help
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <cerrno>
//define opcode for later use
enum opcode {
RRQ = 1,
WRQ,
DATA,
ACK,
ERROR
};
void handle_write(struct sockaddr_in * sock_info, char* filename, int BUF_LEN){
//printf("Received write request + %d\n", WRQ);
return;
}
void handle_error(unsigned short int * opcode_ptr, char* buffer, socklen_t sockaddr_len, int server_socket, struct sockaddr_in * sock_info, const char* errormsg){
ssize_t n;
*opcode_ptr = htons(ERROR);
*(opcode_ptr + 1) = htons(1);
*(buffer + 4) = 0;
//memcpy(buffer+4, errormsg, strlen(errormsg));
intr_send:
n = sendto(server_socket, buffer, 5, 0,
(struct sockaddr *)sock_info, sockaddr_len);
if(n < 0) {
if(errno == EINTR) goto intr_send;
perror(errormsg);
exit(-1);
}
return;
}
int main() {
int BUF_LEN = 516;
ssize_t n;
char buffer[BUF_LEN];
socklen_t sockaddr_len;
int server_socket;
struct sigaction act;
unsigned short int opcode;
unsigned short int * opcode_ptr;
struct sockaddr_in sock_info;
memset(&sock_info, 0, sockaddr_len);
//----------setup the server----------------//
sock_info.sin_addr.s_addr = htonl(INADDR_ANY);
sock_info.sin_port = htons(5743);
sock_info.sin_family = PF_INET;
if((server_socket = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
exit(-1);
}
sockaddr_len = sizeof(sock_info);
if(bind(server_socket, (struct sockaddr *)&sock_info, sockaddr_len) < 0) {
perror("bind");
exit(-1);
}
getsockname(server_socket, (struct sockaddr *)&sock_info, &sockaddr_len);
printf("UDP server listening on port: %d\n", ntohs(sock_info.sin_port));
//----------setup the server----------------//
while(1){
intr_recv:
n = recvfrom(server_socket, buffer, BUF_LEN, 0, (struct sockaddr *)&sock_info, &sockaddr_len);
if(n < 0) {
if(errno == EINTR) goto intr_recv;
perror("recvfrom()");
exit(-1);
}
opcode_ptr = (unsigned short int *)buffer;
opcode = ntohs(*opcode_ptr); //the opcode will be either RRQ or WRQ according to the test
if(opcode != RRQ && opcode != WRQ) {
/* Illegal TFTP Operation */
handle_error(opcode_ptr, buffer, sockaddr_len, server_socket, &sock_info, "invalid command");
}
else {
if(fork() == 0) {
/* Child - handle the request */
FILE* fd;
char* filename;
filename = strdup(buffer+2); //this is the filename to be read (i.e. a.txt)
printf("request received\n");
char data[512];
//----------------------------------handle read request-------------------------------------//
if(opcode == RRQ){
int blocknumber = 0;
int i = 0; //counter for loop
fd = fopen(filename, "r");
free(filename);
//uint8_t data[512];
ssize_t datalen, n;
int done = 0; //this is a boolean indicator that indicates whether the packet transfering process is done or not.
while(!done){
datalen = fread(data, 1, 512, fd);
blocknumber++;
if(datalen < 512){
done = 1; //according to rfc 1350, the last packet will have a data length less than 512 bytes.
}
//for(i = 5; i > 0; i--){
*opcode_ptr = htons(DATA);
opcode = ntohs(*opcode_ptr);
*(opcode_ptr + 1) = htons(blocknumber);
memcpy(buffer + 4, data, datalen);
buffer[datalen + 4] = '\0';
//*(buffer + 4) = 0;
//printf("%d %s\n", datalen, buffer+2);
n = sendto(server_socket, buffer, 4 + datalen, 0, (struct sockaddr *)&sock_info, sockaddr_len);
if(n < 0){
perror("sendto() failed");
exit(-1);
}
//printf("done %d\n", done);
//char buffer[512];
n = recvfrom(server_socket, buffer, sizeof(buffer), 0, (struct sockaddr *)&sock_info, &sockaddr_len);
opcode_ptr = (unsigned short int *)buffer;
opcode = ntohs(*opcode_ptr);
if(n >= 0 && n < 4){
//handle_error(opcode_ptr, buffer, sockaddr_len, server_socket, &sock_info, "invalid request size");
}
if(n > 4){
break;
}
//}
//if(i != 0){
// printf("Transfer timeout!\n");
// exit(1);
//}
//printf("opcode is %d\n", opcode);
if(opcode == ERROR){
printf("Error received\n");
exit(1);
}
if(opcode != ACK){
printf("Invalid message received\n");
exit(1);
}
}
}
//----------------------------------handle read request-------------------------------------//
//----------------------------------handle write request------------------------------------//
//----------------------------------handle write request------------------------------------//
close(server_socket);
break;
}
else {
/* Parent - continue to wait */
}
}
}
return EXIT_SUCCESS;
}
I read your code but not tested by executing.
Compareing with RFC 1350, what I found are
The data field is upto 512 bytes, so 512-byte buffer is not enough because there are no room for the header (Opcode and Block #). You need at least 4 more bytes.
You write the data from buffer + 2 via memcpy(). This should destroy the block number. It seems buffer + 4 should be used instead.
buffer[datalen + 2] = '\0'; shouldn't be needed. I think you should remove it because it will destroy the data or cause buffer overrun.
You should close the file opened after handling read request.
i want to send a file from client to server through socket . yes it sends a file but the received file in the server is not full or complete like the original one.
So the test file originally has "this is a test" in it, and the received file has "this"
yes it's only 4 letters
i tried to change the original one becomes "MyMomGoesToTheMarket"
and received file has "MyMo" . still 4 letters which is not what i expect.
anyone know how to solve this problem and the solution ?
Here is the client :
#include "stdafx.h"
#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
using namespace std;
SOCKET clientsock;
WSADATA winsock;
sockaddr_in serverAddr , addr;
int Addrlen = sizeof(serverAddr);
FILE *File;
unsigned long Size;
void startClient() {
WSAStartup(MAKEWORD(2,2), &winsock);
if(LOBYTE(winsock.wVersion) != 2 || HIBYTE(winsock.wVersion) != 2 ){
WSACleanup();
}
clientsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(6091);
connect(clientsock,(sockaddr*)&addr,sizeof(addr));
printf("socket connected... \n");
}
void sending() {
//preparing the file
ifstream myfile;
myfile.open("B:\RelativeLayout.txt",ios::in | ios::binary | ios::ate);
if(myfile.is_open()) {
printf("File open OK ! \n ");
}else {
printf("File not open ! \n ", WSAGetLastError());
}
//preparing the file size
long Size ;
myfile.seekg(0,fstream::end);
Size = myfile.tellg();
myfile.close();
printf("File Size : %d bytes.\n ",Size);
char cisi[10];
sprintf(cisi, "%i",Size);
send(clientsock,cisi,10,0); // file size sent
//sending the file
char *rbuffer;
myfile.open("B:\RelativeLayout.txt",ios::in | ios::binary | ios::ate);
if(myfile.is_open()) {
myfile.seekg(0, ios::beg);
rbuffer = new char[Size];
myfile.read(rbuffer, Size);
//send(clientsock, rbuffer, Size, 0);
int j = send(clientsock, rbuffer, Size, NULL); //send to server
if (j == -1){
cout << "Error sending file to server :(" << endl;
}else {
cout << " sending file to server succeed" << endl;
}
myfile.close();
}
}
int _tmain(int argc, _TCHAR* argv[])
{
startClient();
sending();
system("PAUSE");
return 0;
}
and here is the server code :
#include "stdafx.h"
#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
#include <fstream>
using namespace std;
SOCKET servsocket, ClientAcc;
WSAData winsock;
sockaddr_in addr,incomingAddress;
int addrlen = sizeof(sockaddr_in);
int addresslen = sizeof(incomingAddress);
char *Filesize = new char[1024];
long Size;
void start() {
//socket initialization
WSAStartup(MAKEWORD(2,2), &winsock);
//socket check
if(LOBYTE(winsock.wVersion) !=2 || HIBYTE(winsock.wVersion) != 2 ) {
WSACleanup();
}
servsocket = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);
addr.sin_family = AF_INET;
addr.sin_port = htons(6091);
bind(servsocket, (sockaddr*)&addr, sizeof(addr));
listen(servsocket, 5);
ClientAcc = accept(servsocket, (sockaddr*)&incomingAddress, &addresslen);
char *ClientIP = inet_ntoa(incomingAddress.sin_addr);
int ClientPort = ntohs(incomingAddress.sin_port);
printf("Client Connected ... \n");
printf("IP : %s:%d\n", ClientIP, ClientPort);
}
void receiving() {
//receive the file size
recv(ClientAcc,Filesize,1024,0);
Size = atoi((const char*)Filesize);
printf("File size : %d\n",Size);
//receive the file
char *rbuffer;
rbuffer = new char[Size];
int k = recv(ClientAcc, rbuffer, sizeof(rbuffer), NULL);
if (k < 0){
cout << "Error uploading file" << endl;
}else {
fstream file;
file.open("B:\FileReceived.txt", ios::out|ios::binary| ios::ate);
file.write(rbuffer, sizeof(rbuffer));
file.close();
cout << "File received!" << endl;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
start();
receiving();
system("PAUSE");
return 0;
}
In your server code's recv function, you're passing in sizeof(rbuffer) as the amount of bytes to read in from the socket. rbuffer is a pointer however, and thus taking a sizeof it will return the size of a pointer on your architecture , which is typically 4 or 8 bytes, and since your server code is only reading 4 bytes, sizeof(rbuffer) would return 4 on your system.
To solve this, you need to pass in either Size-1 or strlen(rbuffer)-1 into the call to
int k = recv(ClientAcc, rbuffer, sizeof(rbuffer), NULL);
So it would look like this:
int k = recv(ClientAcc, rbuffer, Size-1, NULL);
This would actually read up to Size-1 bytes from the socket. You would then need to add the null terminator to the end of rbuffer.
rbuffer[k] = '\0';
Additionally, you need to make the same change in this line:
file.write(rbuffer, sizeof(rbuffer));
Which has the same problem as before - it only writes (in this case 4) bytes from rbuffer.
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