Seg. fault in Multithreaded UDP server - c++

Background:
I have a UDP server that can process clients' requests concurrently. Each client sends two datagrams to the server.
First datagram (Type - 1, Client num)
Second datagram (Type - 2, Client num)
To process all clients concurrently, I initially create a fixed number of server threads and one global UDP socket bound to a known port/address. Then each thread starts to run wherein they block on recvfrom() call on the same global socket. Whichever thread receives a datagram first checks
the type. If it is type 1, it generates a "special" number for the client num it received and stores it. It it is type 2, it sends back the stored "special" number for that client.
Server program:
#define SIZE 1024
int status;
int tnum;
int i;
vector<pthread_t> tid;
struct sockaddr_in server_sock_addr;
const char *server_addr = "127.0.0.1";
int sock;
int reuse = 1;
socklen_t addr_len = sizeof(sockaddr_in);
unordered_map<int, int> dic;
void report(int status){
if(status < 0){
perror("Error");
exit(EXIT_FAILURE);
}
}
void* server_func(void *arg){
int bytes;
char *buf = (char*)malloc(SIZE);
struct sockaddr_in client_sock_addr;
int type;
int num;
while(1){
bytes = recvfrom(sock, buf, SIZE, 0, (sockaddr*)&client_sock_addr, &addr_len);
cout<<bytes<<endl;
report(bytes);
memmove(&type, buf, sizeof(int));
memmove(&num, buf + sizeof(int), sizeof(int));
if(type == 1){
dic[num] = num * 1000;
}
else if(type == 2){
while(dic.find(num) == dic.end()){
};
memset(buf, 0, SIZE);
memmove(buf, &dic[num], sizeof(int));
status = sendto(sock, buf, sizeof(int), 0, (sockaddr*)&client_sock_addr, addr_len);
report(status);
cout<<"Mapped number is "<<num<<" - "<<dic[num]<<endl;
}
else{
report(-1);
}
}
free(buf);
}
int main() {
cout<<"-------------------------------------------"<<endl;
cout<<"SERVER STARTED on port 5000"<<endl;
cout<<"-------------------------------------------"<<endl;
tnum = 4;
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
bzero((char*)&server_sock_addr, sizeof(server_sock_addr));
server_sock_addr.sin_family = AF_INET;
server_sock_addr.sin_port = htons(5000);
inet_aton(server_addr, &server_sock_addr.sin_addr);
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int));
status = bind(sock, (struct sockaddr*)&server_sock_addr, sizeof(server_sock_addr));
report(status);
tid.resize(tnum);
dic.clear();
for (i = 0; i < tnum; i++) {
status = pthread_create(&tid[i], NULL, server_func, NULL);
report(status);
}
for (i = 0; i < tnum; i++) {
pthread_join(tid[i], NULL);
}
close(sock);
return 0;
}
Client program
#define SIZE 1024
int num;
int i;
vector<pthread_t> tid;
vector<int> client_num;
const char *server_addr = "127.0.0.1";
socklen_t addr_len = sizeof(sockaddr_in);
void report(int status){
if(status < 0){
perror("Error");
exit(EXIT_FAILURE);
}
}
void* client_func(void *arg){
struct sockaddr_in server_sock_addr;
int cnum = *((int*)arg);
char *buf = (char*)malloc(SIZE);
int type;
int sock;
int bytes;
int status;
int res;
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
bzero((char*)&server_sock_addr, sizeof(server_sock_addr));
server_sock_addr.sin_family = AF_INET;
server_sock_addr.sin_port = htons(5000);
status = inet_aton(server_addr, &server_sock_addr.sin_addr);
report(status);
type = 1;
memset(buf, 0, SIZE);
memmove(buf, &type, sizeof(int));
memmove(buf + sizeof(int), &cnum, sizeof(int));
status = sendto(sock, buf, 2 * sizeof(int), 0, (sockaddr*)&server_sock_addr, addr_len);
report(status);
type = 2;
memset(buf, 0, SIZE);
memmove(buf, &type, sizeof(int));
memmove(buf + sizeof(int), &cnum, sizeof(int));
status = sendto(sock, buf, 2 * sizeof(int), 0, (sockaddr*)&server_sock_addr, addr_len);
report(status);
bytes = recvfrom(sock, buf, SIZE, 0, (sockaddr*)&server_sock_addr, &addr_len);
report(bytes);
memcpy(&res, buf, sizeof(int));
cout<<"Mapped number from the server for Client - "<<cnum<<" is "<<res<<endl;
free(buf);
close(sock);
}
int main(int argc, char *argv[]) {
int status;
if(argc < 2){
cout<<"Enter number of threads"<<endl;
exit(EXIT_FAILURE);
}
num = atoi(argv[1]);
tid.resize(num);
client_num.resize(num);
for (i = 0; i < num; i++) {
client_num[i] = i+1;
status = pthread_create(&tid[i], NULL, client_func, &client_num[i]);
}
for (i = 0; i < num; i++) {
pthread_join(tid[i],NULL);
}
cout << "Requested duration has ended. Finishing the program." << endl;
return 0;
}
Problem I am facing:
When 500 clients send datagrams concurrently, the server works as expected only when I include some kind of COUT statement after the recvfrom() call(First line in while(1) loop). If I delete that cout statement, it gives Segmentation fault because the server gets stuck on the while() loop to check whether an item exists or not. while(dic.find(num) == dic.end()){};. I am not able to figure out the reason for this problem. Please provide me your suggestions.
Thanks.
EDIT:
Having a mutex lock on "dic" data-structure(while writing it) solves the problem(I do not need to use "cout" anymore), but I want to confirm whether this is absolutely the correct fix and want to learn anyother subtle points that I could out of this program, because I'd building a much bigger version of this program soon with lots of global datastructures to be shared by all threads

Related

Garbage at the end of buffer socket

When I send 5 through a serial terminal, recv() outputs the sent data, and then corrupted garbage (5╠╠╠╠╠╠╠╠☺0). This is my code:
#include <winsock2.h>
#include <ws2bth.h>
#include <Windows.h>
#include <iostream>
#include <string.h>
#pragma comment(lib, "Ws2_32.lib")
using namespace std;
int i;
unsigned int aaddr[6];
void send2(string in) {
WSADATA wsa;
memset(&wsa, 0, sizeof(wsa));
int error = WSAStartup(MAKEWORD(2, 2), &wsa);
SOCKET btSocket = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
SOCKADDR_BTH sockAddr;
memset(&sockAddr, 0, sizeof(sockAddr));
sockAddr.addressFamily = AF_BTH;
sockAddr.serviceClassId = RFCOMM_PROTOCOL_UUID;
sockAddr.port = BT_PORT_ANY;
BTH_ADDR tmpaddr = 0;
sscanf_s("7C:9E:BD:4C:BF:B2", "%02x:%02x:%02x:%02x:%02x:%02x", &aaddr[0], &aaddr[1], &aaddr[2], &aaddr[3], &aaddr[4], &aaddr[5]);
*&sockAddr.btAddr = 0;
for (i = 0; i < 6; i++) {
tmpaddr = (BTH_ADDR)(aaddr[i] & 0xff);
*&sockAddr.btAddr = ((*&sockAddr.btAddr) << 8) + tmpaddr;
}
connect(btSocket, (SOCKADDR*)&sockAddr, sizeof(sockAddr));
char charIn[28];
strcpy_s(charIn, in.c_str());
send(btSocket, charIn, (int)strlen(charIn), 0);
closesocket(btSocket);
}
void recv2() {
WSADATA wsa;
memset(&wsa, 0, sizeof(wsa));
int error = WSAStartup(MAKEWORD(2, 2), &wsa);
SOCKET btSocket = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
SOCKADDR_BTH sockAddr;
memset(&sockAddr, 0, sizeof(sockAddr));
sockAddr.addressFamily = AF_BTH;
sockAddr.serviceClassId = RFCOMM_PROTOCOL_UUID;
sockAddr.port = BT_PORT_ANY;
BTH_ADDR tmpaddr = 0;
sscanf_s("7C:9E:BD:4C:BF:B2", "%02x:%02x:%02x:%02x:%02x:%02x", &aaddr[0], &aaddr[1], &aaddr[2], &aaddr[3], &aaddr[4], &aaddr[5]);
*&sockAddr.btAddr = 0;
for (i = 0; i < 6; i++) {
tmpaddr = (BTH_ADDR)(aaddr[i] & 0xff);
*&sockAddr.btAddr = ((*&sockAddr.btAddr) << 8) + tmpaddr;
}
connect(btSocket, (SOCKADDR*)&sockAddr, sizeof(sockAddr));
const int outLen = 1;
char charOut[outLen];
recv(btSocket, charOut, outLen, 0);
cout << charOut;
closesocket(btSocket);
cout << WSAGetLastError();
}
int main() {
recv2();
}
Where are all these characters coming from?
You should NOT reinitialize Winsock, or recreate the Bluetooth socket, on every send and read. Initialize Winsock one time, preferably at app startup. And then create 1 socket and reuse it as needed.
Also, you don't need the charIn[] buffer in send2() at all, as you can pass in to send():
send(btSocket, in.c_str(), (int)in.size(), 0);
In any case, your garbage issue is because you are not sending a null terminator after the sent data, and you are not null-terminating the buffer you are reading into, but you are displaying the buffer as if it were null-terminated. You need to pay attention to the return value of recv() and display only as many bytes as you actually receive, eg:
const int outLen = 1;
char charOut[outLen+1];
int numBytes = recv(btSocket, charOut, outLen, 0);
if (numBytes > 0) {
charOut[numBytes] = '\0';
cout << charOut;
}
Or:
const int outLen = 1;
char charOut[outLen];
int numBytes = recv(btSocket, charOut, outLen, 0);
if (numBytes > 0) {
cout.write(charOut, numBytes);
}

C++ Socket API "Heartbeat"

I'm trying to make a simple heartbeat check from client to server and vice-versa, if connection on either is broken off unexpectedly it prints a message and calls closesocket.
I spent 8 hours on this and it still isn't acceptable to my mentor. Right now I got something that works, but if breakpoint is placed before while loop and connected client is forcefully closed, trying to go past breakpoint causes crash when it should break the loop and write out error.
Server side code:
int main(int argc, char *argv[])
{
SOCKET s, sa;
WSAData oWSAData;
WORD wVersion = 0x0001;
WSAStartup(wVersion, &oWSAData);
s = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in srv_address;
memset(&srv_address, 0, sizeof(srv_address));
srv_address.sin_family = AF_INET;
srv_address.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
srv_address.sin_port = htons(1099);
bind(s, (sockaddr*) &srv_address, sizeof(srv_address));
int l = listen(s, 10);
if (l < 0)
printf("Listen error\n");
else
{
printf("Listen OK. Listening on port %u\n",
htons(srv_address.sin_port));
sa = accept(s, NULL, NULL);
while (true)
{
char buffer[1000];
int nRecvLen = recv(sa, buffer, 999, 0);
buffer[nRecvLen] = '\0';
int r = recv(sa, NULL, 0, 0);
if (r == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)
{
printf("Konekcija je naglo prekinuta!\n");
break;
}
else
{
if (nRecvLen > 0)
{
for (int i = 0; i < nRecvLen; i++)
{
cout << buffer[i];
}
}
}
}
closesocket(sa);
closesocket(s);
}
WSACleanup();
return 0;
}
and client side:
int main()
{
SOCKET s;
WSAData oWSAData;
WORD wVersion = 0x0001;
WSAStartup(wVersion, &oWSAData);
s = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in srv_address;
memset(&srv_address, 0, sizeof(srv_address));
srv_address.sin_family = AF_INET;
srv_address.sin_addr.S_un.S_un_b.s_b1 = xxx;
srv_address.sin_addr.S_un.S_un_b.s_b2 = xxx;
srv_address.sin_addr.S_un.S_un_b.s_b3 = x;
srv_address.sin_addr.S_un.S_un_b.s_b4 = xxx;
srv_address.sin_port = htons(1099);
int c = connect(s, (sockaddr*) &srv_address, sizeof(srv_address));
if (c < 0)
{
printf("Connection error\n");
cout << (WSAGetLastError());
}
else
{
string l = "Heartbeat\n";
int p = l.size();
char buff[1000];
strcpy_s(buff, l.c_str());
printf("Connected\n");
while (true)
{
if (send(s, buff, p, 0) > 0)
{
Sleep(1000);
}
else
{
printf("Konekcija je naglo prekinuta\n");
shutdown(s, SD_BOTH);
closesocket(s);
break;
}
}
WSACleanup();
return 0;
}
}

What`s wrong with this socket select code?

#include <stdio.h>
#include <time.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#pragma comment(lib, "WS2_32.lib")
#define IP_ADDRESS "127.0.0.1"
#define PORT 20000
#define BUF_SIZE 64
#undef FD_SETSIZE
#define FD_SETSIZE 10000
void shuffle_buffer(char* buf, size_t size);
SOCKET create_socket();
void send_data(SOCKET sock);
int main()
{
WSADATA ws;
if (WSAStartup(MAKEWORD(2, 2), &ws) != 0)
{
printf("Init Windows Socket Failed::%d\n", GetLastError());
return -1;
}
const int CLIENT_SIZE = 1;
SOCKET socks[CLIENT_SIZE];
struct timeval tv = { 0, 10 };
fd_set fd_read, fd_write;
FD_ZERO(&fd_read);
FD_ZERO(&fd_write);
for (int i = 0; i < CLIENT_SIZE; i++) {
SOCKET sock = create_socket();
socks[i] = sock;
FD_SET(sock, &fd_write);
FD_SET(sock, &fd_read);
}
Sleep(1000);
int number_to_recv = CLIENT_SIZE;
while (number_to_recv > 0) {
int ret = select(CLIENT_SIZE, &fd_read, &fd_write, NULL, &tv);
for (int i = 0; i < CLIENT_SIZE; i++) {
if (FD_ISSET(socks[i], &fd_read)) {
char buf[BUF_SIZE];
int n = recv(socks[i], buf, BUF_SIZE, 0);
buf[n] = 0;
printf("%s\n", buf);
number_to_recv--;
}
if (FD_ISSET(socks[i], &fd_write)) {
send_data(socks[i]);
FD_CLR(socks[i], &fd_write);
//Sleep(1);
}
}
//printf("ret and number : %d, %d\n", ret, number_to_recv);
}
for (int i = 0; i < CLIENT_SIZE; i++) {
closesocket(socks[i]);
}
WSACleanup();
}
SOCKET create_socket()
{
SOCKET cli_sock;
struct sockaddr_in addr;
if ((cli_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
printf("Create Socket Failed::%d\n", GetLastError());
return -1;
}
//inet_pton
memset(addr.sin_zero, 0x00, 8);
addr.sin_family = AF_INET;
inet_pton(AF_INET, IP_ADDRESS, (void*)(&addr.sin_addr.s_addr));
addr.sin_port = htons(PORT);
if (connect(cli_sock, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
{
printf("Connect Error::%d\n", GetLastError());
return -1;
}
return cli_sock;
}
void send_data(SOCKET sock)
{
const int SEND_SIZE = BUF_SIZE / 2;
char buf[SEND_SIZE] = { 0 };
memset(buf, 'a', SEND_SIZE);
shuffle_buffer(buf, SEND_SIZE);
if (send(sock, buf, SEND_SIZE, 0) == SOCKET_ERROR)
{
printf("Send Info Error::%d\n", GetLastError());
}
}
void shuffle_buffer(char* buf, size_t size)
{
for (int i = 0; i < size; i++) {
buf[i] += int(rand() % 26);
}
}
Code above is a socket client using select model run on Win10, the problem is after I send data, but I can not receive data(I am sure that server has sent back data), this code below doesn`t run, so what is the problem? Thanks
The first parameter in select is maxfdp, and I know the difference between Win and Unix, so on Windows, this parameter seems not necessary, and I can write data,
but can not receive it.
if (FD_ISSET(socks[i], &fd_read)) {
char buf[BUF_SIZE];
int n = recv(socks[i], buf, BUF_SIZE, 0);
buf[n] = 0;
printf("%s\n", buf);
number_to_recv--;
}
select removes the sockets from the fd_set if they are not readable/writable. You need to add them back in before the next time you call select.
The reason your code can write data is because sockets start out being writable, so they will still be set in fd_write and your code will write data. They don't start out being readable, if no data has been received yet, so they'll be removed from the fd_read set and then your code stops checking whether they are readable.

Multi threaded HTTP server socket hangs with CLOSE_WAIT

I have a C++ server application. The server application is acting as a HTTP
server in this case. With the large number of requests socket move to the
CLOSE_WAIT state.With small number of requests its working fine.
void *task1(void *);
static int connFd;
int noThread = 0;
int main()
{
int pId, portNo, listenFd;
socklen_t len; //store size of the address
bool loop = false;
struct sockaddr_in svrAdd, clntAdd;
pthread_t threadA[500];
portNo = 9898 ;
cout<<"td::string::npos = "<<std::string::npos<<endl;
if((portNo > 65535) || (portNo < 2000))
{
cout<<"Please enter a port number between 2000 - 65535";
return 0;
}
//create socket
listenFd = socket(AF_INET, SOCK_STREAM, 0);
if(listenFd < 0)
{
cout<< "Cannot open socket"<<endl;
return 0;
}
bzero((char*) &svrAdd, sizeof(svrAdd));
svrAdd.sin_family = AF_INET;
svrAdd.sin_addr.s_addr = INADDR_ANY;
svrAdd.sin_port = htons(portNo);
//bind socket
if(bind(listenFd, (struct sockaddr *)&svrAdd, sizeof(svrAdd)) < 0)
{
cout<<"Cannot bind"<<endl;;
return 0;
}
listen(listenFd, 5);
len = sizeof(clntAdd);
while (noThread < 500)
{
cout<<"Listening"<<endl;
//this is where client connects. svr will hang in this mode until client conn
connFd = accept(listenFd, (struct sockaddr *)&clntAdd, &len);
if (connFd < 0)
{
cout<<"Cannot accept connection"<<endl;
return 0;
}
else
{
cout<<"Connection successful" <<endl;
}
//pthread_create(&threadA[noThread], NULL, test::task1, NULL);
//thr_create(&threadA[noThread], NULL, task1, NULL);
pthread_create(&threadA[noThread], NULL, task1, NULL);
noThread++;
cout<<"Number of noThread :"<< noThread;
}
for(int i = 0; i < 500; i++)
{
pthread_join(threadA[i], NULL);
//thr_join(threadA[i], NULL);
cout<<"inside join"<<i;
}
}
void *task1 (void *dummyPt)
{
cout<<"Thread No: " << pthread_self();
char test[1000];
bzero(test, 1001);
bool loop = false;
int t=0;
while(t==0)
{
bzero(test, 1001);
read(connFd, test, 1001);
string t1(test);
if(tester.find("connection_request")!=std::string::npos){
if(connFd)
{
cout<<"T1 :"<<t1<<endl;
send(connFd, "HTTP/1.0 200 OK\n\n", 17, 0);
write(connFd,"Test Response",13);
}
else
cout << "Problem With collection FD";
t=1;
}
}
cout<<"Closing thread and conn"<<endl;
close(connFd);
noThread--;
return NULL;
}

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