client server in c- file transfer issue for larger files - c

The below code works fine for smaller files where the last packet contains data less than maximum length, the function exit properly by displaying file received.
How ever if the last packet or buffer of file being transmitted contains exact number as the size of receiving buffer array 512 in my case. then th program keeps waiting for next packet.
All files with size multiple of 512 in my case stuck.
Below is the code:
CLIENT code for receiving:
void receiveFile() {
printf("inside receiveFile method\n");
char* fr_name = "final.txt";
int i;
FILE *fr = fopen(fr_name, "a");
int LENGTH = 512;
int fileLength=0;
char revbuf[LENGTH];
if (fr == NULL) {
printf("File %s Cannot be opened.\n", fr_name);
} else {
printf("starting to write the file\n");
bzero(revbuf, LENGTH);
int fr_block_sz = 0;
i=0;
while ((fr_block_sz = recv(4, revbuf, LENGTH, 0)) > 0) {
fileLength+=fr_block_sz;
i++;
printf("Received buffer: %d, %d\n",fr_block_sz,i);
int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);
if (write_sz < fr_block_sz) {
error("File write failed.\n");
}
bzero(revbuf, LENGTH);
if (fr_block_sz == 0 || fr_block_sz != 512) {
break;
}
}
if (fr_block_sz < 0) {
if (errno == EAGAIN) {
printf("recv() timed out.\n");
} else {
fprintf(stderr, "recv() failed due to errno = %d\n", errno);
}
}
printf("FILE RECEIVED....Total Bytes received:%d \n",fileLength);
}
fclose(fr);
}
Server for Receiving the file:
void sendFile() {
printf("inside sendFile method\n");
char* fs_name = "mb.txt";
int LENGTH = 512;
int sfileLength=0;
char sdbuf[LENGTH];
int i=0;
printf("[Client] Sending %s to the Server... \n", fs_name);
FILE *fs = fopen(fs_name , "r");
if (fs == NULL) {
perror("ERROR: File not found.\n");
exit(1);
}
bzero(sdbuf, LENGTH);
int fs_block_sz;
while ((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs)) > 0) {
i++;
printf("Sent:%d , %d \n", fs_block_sz,i);
sfileLength+=fs_block_sz;
if (send(4, sdbuf, fs_block_sz, 0) < 0) {
fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n",
fs_name, errno);
break;
}
bzero(sdbuf, LENGTH);
}
printf("File sent.... Total Bytes:%d\n", sfileLength);
fclose(fs);
}

if (fr_block_sz == 0 || fr_block_sz != 512) {
break;
}
Remove this code. The first part of the test can never be true due to the 'while' condition, and the second part is unnecessary for the same reason.

Related

Can not use socket after file transfer - C Socket

In here I am sending file name first then sending the file in chunks, then trying to read the received message but it is just freezing. No respond. But after loop if I shutdown the WR shutdown(connfd,SHUT_WR); It is working fine. Though I should be able to send message again, if I do this I can not do that.
CLIENT.C
write(sockfd, fname,100);
FILE *fp = fopen(fname,"rb");
if(fp==NULL)
{
printf("File opern error");
exit(1);
}
int hi = 0;
while(1)
{
/* First read file in chunks of 256 bytes */
unsigned char buff[1024]={0};
int nread = fread(buff,1,1024,fp);
/* If read was success, send data. */
if(nread > 0)
{
hi++;
//printf("Sending \n");
write(sockfd, buff, nread);
}
if (nread < 1024)
{
if (feof(fp))
{
printf("File transfer completed!\n");
}
if (ferror(fp))
printf("Error reading\n");
break;
}
}
char fname2[100];
// cant read
read(sockfd, fname2, 100);
printf("File Name: %s\n",fname2);
SERVER.C
FILE *fp;
int bytesReceived = 0;
char recvBuff[1024];
char fname[100];
char fname2[100];
read(newsockfd, fname, 100);
//strcat(fname,"AK");
printf("File Name: %s\n",fname);
printf("Receiving file...");
fp = fopen(fname, "ab");
if(NULL == fp)
{
printf("Error opening file");
}
long double sz=1;
/* Receive data in chunks of 256 bytes */
printf("\nCompleted.\n");
int hi = 0;
while((bytesReceived = read(newsockfd, recvBuff, 1024)) > 0)
{
hi++;
sz++;
fwrite(recvBuff, 1,bytesReceived,fp);
}
printf("Not pring this this!");
if(bytesReceived < 0)
{
printf("\n Read Error \n");
}
write(newsockfd, "SayGee",100);
I had to send the size of the file, then check from the other side inside loop. It was in deadlock.I found the solution. So thanks anyway!

ssh_scp_read returns garbage

I'm trying to download a file from my server; both the client and the server are Linux, yet ssh_scp_read() returns an incorrect integer. According to the documentation the function writes up to 65536 bytes, yet is only reading 16384 when the file is 37980, but that's not my main concern; near the end of this 16384 bytes it starts to fill the buffer with NULL garbage, that will then be written to the file.
The creation of recursive directories works fine; the problem is downloading files larger than 16384 bytes. At this point I'll use sftp instead of scp, but I would like to know what I am doing wrong.
This is the function code:
int get(ssh_session gno_ses,ssh_scp scp)
{
int rc;
int size, permissions;
char *buff, *filename, path[PATH_MAX];
while(1)
{
rc = ssh_scp_pull_request(scp);
switch (rc)
{
// cases [...]
case SSH_SCP_REQUEST_NEWFILE:
size = ssh_scp_request_get_size(scp);
printf("Size is %d\n",size);
filename = strdup(ssh_scp_request_get_filename(scp));
permissions = ssh_scp_request_get_permissions(scp);
FILE *file;
file = fopen(filename, "w+");
if (!file)
{
ssh_scp_deny_request(scp,"Unable to open");
fprintf(stderr, " %s: %s\n", filename, strerror(errno));
fclose(file);
break;
}
buff = malloc(size);
printf("Size of buffer is %d\n", size);
if (!buff)
{
fprintf(stderr, "\nBuff memory allocation error.\n");
return SSH_ERROR;
}
if( ssh_scp_accept_request(scp) != SSH_OK)
{
fprintf(stderr, "Error accepting request: %s\n", ssh_get_error(gno_ses));
break;
}
do
{
rc = ssh_scp_read(scp, buff, size);
if (rc == SSH_ERROR)
{
fprintf(stderr, "Error receiving file data: %s\n", ssh_get_error(gno_ses));
break;
}
if (fwrite(buff, 1, size, file) != size)
{
perror("Error at writting to file: ");
break;
}
printf("ssh_scp_read got %d\n",rc);
} while (rc != 0);
fclose(file);
free(filename);
free(buff);
break;
}
}
return SSH_OK;
}
And this is the output:
Size is 37980
Size of buffer is 37980
ssh_scp_read got 16384
ssh_scp_read got 16384
ssh_scp_read got 5212
Error receiving file data: ssh_scp_read called under invalid state
Any input would be appreciated.
The problem was that I was writing size bytes when indeed scp_scp_read() had reported that it had read less than that:
rc = ssh_scp_read(scp, buff, size);
fwrite(buff, 1, size, file)
The fix is to write only rc bytes:
int len_loop = size;
int len;
do
{
rc = ssh_scp_read(scp, buff, size);
if (rc == SSH_ERROR || rc < 0)
{
fprintf(stderr, "Error receiving file data: %s\n", ssh_get_error(gno_ses));
break;
}
else if (!rc)
{
break;
}
len = fwrite(buff, 1, rc, file);
if (len != rc)
{
perror("Error at writting to file: ");
break;
}
printf("ssh_scp_read got %d\n",rc);
len_loop -= rc;
} while(len_loop);
change your inner loop as
int len = size;
do
{
rc = ssh_scp_read(scp, buff, size);
if (rc == SSH_ERROR)
{
fprintf(stderr, "Error receiving file data: %s\n",
ssh_get_error(gno_ses));
break;
}
if (fwrite(buff, 1, rc, file) != size)
{
perror("Error at writting to file: ");
break;
}
printf("ssh_scp_read got %d\n",rc);
len-=rc;
} while (len);

In c socket, why my server can't receive the whole content?

I am new in this field, and writing one server and client, but it really confusing that I can't get all the content, but some small clip.
My server code:
read(connfd, name, 20);
//recv(connfd,name,1024,0);
char* a=name;
while(a[0]!='\n'){
a++;
}
a[0]='\0';
printf("name:%s\n", name);
read(connfd, size, 20);
printf("size:%s\n", size);
recv(connfd,buf,8192,0);
printf("buf:%s\n", buf);
if((stream = fopen(name,"w+t"))==NULL){
printf("The file was not opened! \n");
}
int write_length = fwrite(buf,sizeof(char),8192,stream);
bzero(buf,8192);
if(put){
char *res="OK\n";
write(connfd, res, 1024);
}
fclose(stream);
and my client code is:
char buffer[8192];
bzero(buffer,8192);
char * put="PUT\n";
if ((write(fd, put, 8192)) <= 0) {
if (errno != EINTR) {
fprintf(stderr, "Write error: %s\n", strerror(errno));
exit(0);
}
}
struct stat st ;
stat( put_name, &st );
char str[100];
sprintf(str, "%d", st.st_size);
int len;
char *current=NULL;
len=strlen(put_name);
char sendname[1024];
strcpy(sendname,put_name);
strcat(sendname,"\n");
write(fd, sendname, 10);
strcat(str,"\n");
write(fd, str, 10);
FILE *stream;
if((stream = fopen(put_name,"r"))==NULL)
{
printf("The file was not opened! \n");
exit(1);
}
int lengsize = 0;
while((lengsize = fread(buffer,1,8192,stream)) > 0){
if(send(fd,buffer,8192,0)<0){
printf("Send File is Failed\n");
break;
}
bzero(buffer, 8192);
}
Now, I can send all content, but can receive part of them. for example, on my mac, server can receive name but the str is neglected, when I printf the str in the server, it shows the content of file. and the content of file is not the whole file content. Some content disappear. Could you tell me why?
The read and write functions are not guaranteed to send or receive the entire message with a single call. Instead, you're expected to sit in a loop, writing the message incrementally until everything has been sent and reading everything incrementally until everything has been read. For example, if you know exactly how much has been sent, you can do this:
char recvBuffer[BUFFER_SIZE];
int bytesRead = 0;
while (bytesRead < BUFFER_SIZE) {
int readThisTime = read(file, recvBuffer + bytesRead, BUFFER_SIZE - bytesRead);
if (readThisTime == -1) {
// handle error...
}
bytesRead += readThisTime;
}
If you don't know exactly how much has been sent, try this:
char recvBuffer[BUFFER_SIZE];
int bytesRead = 0;
while (bytesRead < BUFFER_SIZE) {
int readThisTime = read(file, recvBuffer + bytesRead, BUFFER_SIZE - bytesRead);
if (readThisTime == -1) {
// handle error...
}
if (readThisTime == 0) break; // Done!
bytesRead += readThisTime;
}
You are ignoring the return values of send() and recv(). You MUST check return values!
When sending the file, lengsize receives how many bytes were actually read from the file. Your client is sending too many bytes when lengsize is < 8192 (typically the last block of the file if the file size is not an even multiple of 8192).
But more importantly, although the client is telling the server the file size, the server is ignoring it to know when to stop reading. The server is also ignoring the return value of recv() to know how many bytes were actually received so it knows how many bytes can safely be written to the output file.
Try something more like this instead:
common:
int readData(int s, void *buf, int buflen)
{
int total = 0;
char *pbuf = (char*) buf;
while (buflen > 0) {
int numread = recv(s, pbuf, buflen, 0);
if (numread <= 0) return numread;
pbuf += numread;
buflen -= numread;
total += numread;
}
return total;
}
int sendData(int s, void *buf, int buflen)
{
int total = 0;
char *pbuf = (char*) buf;
while (buflen > 0) {
int numsent = send(s, pbuf, buflen, 0);
if (numsent <= 0) return numsent;
pbuf += numsent;
buflen -= numsent;
total += numsent;
}
return total;
}
int readInt32(int s, int32_t *value)
{
int res = readData(s, value, sizeof(*value));
if (res > 0) *value = ntohl(*value);
return res;
}
int sendInt32(int s, int32_t value)
{
value = htonl(value);
return sendData(s, &value, sizeof(value));
}
char* readStr(int s)
{
int32_t size;
if (readInt32(s, &size) <= 0)
return NULL;
char *str = malloc(size+1);
if (!str)
return NULL;
if (readData(s, str, size) <= 0) {
free(str);
return NULL;
}
str[size] = '\0';
return str;
}
int sendStr(int s, const char *str)
{
int len = strlen(str);
int res = sendInt32(s, len);
if (res > 0)
res = sendData(s, str, len);
return res;
}
server:
char buffer[8192];
char *name = readStr(connfd);
if (!name) {
// error handling ...
sendStr(connfd, "Socket read error");
return;
}
printf("name:%s\n", name);
int32_t filesize;
if (readInt32(connfd, &filesize) <= 0) {
// error handling ...
free(name);
sendStr(connfd, "Socket read error");
return;
}
printf("size:%d\n", filesize);
if ((stream = fopen(name, "wb")) == NULL) {
// error handling ...
printf("The file was not opened!\n");
free(name);
sendStr(connfd, "File not opened");
return;
}
while (filesize > 0) {
int numread = readData(connfd, buf, min(filesize, sizeof(buffer)));
if (numread <= 0) {
// error handling ...
close(stream);
free(name);
sendStr(connfd, "Socket read error");
return;
}
printf("buf:%.*s\n", numread, buf);
if (fwrite(buf, 1, numread, stream) != numread) {
// error handling ...
close(stream);
free(name);
sendStr(connfd, "File write error");
return;
}
filesize -= numread;
}
fclose(stream);
free(name);
sendStr(connfd, "OK");
client:
char buffer[8192];
struct stat st;
if (stat( put_name, &st ) != 0) {
// error handling ...
exit(0);
}
if ((stream = fopen(put_name, "rb")) == NULL) {
// error handling ...
printf("The file was not opened!\n");
exit(0);
}
if (sendStr(fd, put_name) <= 0) {
// error handling ...
close(stream);
exit(0);
}
int32_t filesize = st.st_size;
if (sendInt32(fd, filesize) <= 0) {
// error handling ...
close(stream);
exit(0);
}
int lengsize;
while (filesize > 0) {
lengsize = fread(buffer, 1, min(filesize , sizeof(buffer)), stream);
if (lengsize <= 0) {
printf("Read File Failed\n");
// error handling ...
close(stream);
exit(0);
}
if (sendData(fd, buffer, lengsize) <= 0) {
printf("Send File Failed\n");
// error handling ...
close(stream);
exit(0);
}
filesize -= lengsize;
}
close(stream);
char *resp = readStr(fd);
if (!resp) {
// error handling ...
exit(0);
}
if (strcmp(resp, "OK") == 0)
printf("Send File OK\n");
else
printf("Send File Failed: %s\n", resp);
free(resp);

File partially sent in c

I'm trying to send files using TCP from a windows client to a Linux server in C.
The size of the buffer I use to send the data is 65535. When the size of the file exceeds this value, I get an error saying 'connection reset by peer' or the error code 10054. When the size of the file is less than 65535 bytes, the server receives only a part of it (usually 2760 bytes).
I just want to send files with a maximum size of 50 MB.
This is the part of the windows client that I use to send data:
char *fileName; // pointer to filename
char buf[65535]; // buffer
int fileSize; // # bytes to send
for(i = 0; i < ARRAYSIZE; i++) {
if(selectList[i] != NULL) {
// select file
fileName= selectList[i]; // get path and filename from selectList
printf("=============================================\nSending: %s\n", fileName);
filefd = fopen(fileName, "rb"); // open file
if(filefd == NULL) {
printf("File %s not found\n", fileName);
exit(1);
}
// read and send file
memset(buf, '\0', 65535);
while((fileSize= fread(buf, sizeof(char), 65535, filefd)) > 0) { // read file
if((numberOfBytes = send(sockfd, buf, fileSize, 0)) < 0) { // send buffer
printf("send: %s (Error: %d)\n", filename, WSAGetLastError());
break;
}
printf("#bytes = %i \n", numberOfBytes);
memset(buf, '\0', 65535);
}
printf("File %s send!\n", filename);
// close file after sending it
if(fclose(filefd) < 0) {
printf("fclose: %i", WSAGetLastError());
}
} else if(selectList[0] == NULL) {
printf("no files selected");
}
}
The selectList contains multiple strings such as: C:\Windows\test.txt
The recieve part of the Linux server:
char* fr_name = "/home/MtFS/UploadedFiles/public/testFile.gif";
FILE *fr = fopen(fr_name, "wb");
if(fr == NULL)
printf("[Open_File]file %s cannot be created\n", fr_name);
else {
bzero(revbuf, LENGTH);
int fr_block_sz = 0;
while((fr_block_sz = recv(nsockfd, revbuf, LENGTH, 0)) > 0) {
int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);
if(write_sz < fr_block_sz) {
error("[Write] error\n");
}
bzero(revbuf, LENGTH);
if (fr_block_sz == 0 || fr_block_sz != 512) {
break;
}
}
if(fr_block_sz < 0) {
if (errno == EAGAIN) {
printf("[Receive] time out\n");
}
else {
printf("[Receive] error\n");
exit(1);
}
}
printf("[Receive] succesfull\n");
fclose(fr);
}
What am I doing wrong?
Your problem are those 3 lines of code. That's not the correct way to know that you're done:
if (fr_block_sz == 0 || fr_block_sz != 512) {
break;
}
Also you check against 512 instead of LENGTH. But only 0 means that you're done (assuming your connection is not NONBLOCKED.)
As a side note: you do not have to clear your buffers (bzero, memset) before using them with a read since the read/recv will overwrite the content of the buffers anyway.
I think the culprit is this line in your server
if (fr_block_sz == 0 || fr_block_sz != 512) {
fr_block_sz cab be anything between 1 to 65535 - the size block that you sent.
In your code, when its not 512 so your server is terminating the connection.

C 3G File Transfer Client/Server Linux

I have a problem that I'm hoping is a mistake as I am a bit new to linux C.
I have a server, that sends a file to a client. The code works perfectly fine over a wired connection, 100% success rate every time. However, when I try to run that same code over a 3G USB connection at -65dB (Strong), the client will usually only receive the first 1 or 2 thousand bytes of the file. (Forgive the syntax errors won't let me space properly)
// CLIENT CODE
char* fs_name = "/target/to/send";
char sdbuf[LENGTH]; // Send buffer, LENGTH == 512
printf("Sending %s to the Client... \n", fs_name);
FILE *fs = fopen(fs_name, "r");
if(fs == NULL)
{
fprintf(stderr, "ERROR: File %s not found on server. (errno = %d)\n", fs_name, errno);
exit(1);
}
bzero(sdbuf, LENGTH);
int fs_block_sz;
while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs))>0)
{
if(send(client, sdbuf, fs_block_sz, 0) < 0)
{
fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno);
exit(1);
}
bzero(sdbuf, LENGTH);
}
printf("File send Success\n");
// SERVER CODE
char* fr_name = "/home/file/to/save";
FILE *fr = fopen(fr_name, "a");
if(fr == NULL)
printf("File %s Cannot be opened.\n", fr_name);
else
{
// zero out bytes
bzero(revbuf, LENGTH);
int fr_block_sz = 0;
while((fr_block_sz = recv(sd, revbuf, LENGTH, 0)) > 0) //LENGTH == 512
{
int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);
if(write_sz < fr_block_sz)
{
error("File write failed.\n");
}
bzero(revbuf, LENGTH);
if (fr_block_sz == 0 || fr_block_sz != 512)
{
break;
}
}
// error checking
if(fr_block_sz < 0)
{
if (errno == EAGAIN)
{
printf("recv() timed out.\n");
}
else
{
fprintf(stderr, "recv() failed due to errno = %d\n", errno);
}
fclose(fr);
If anyone out there could shed some light on what I'm doing wrong I would be most appreciative. Thanks for reading.
EDIT: The server is Ubuntu 10.04 and the client is Arch Linux ARM and the type of file being sent is an ARM binary.
I think your main problem is here in your code labeled server but which really looks to be the client. You assume that the recv is going to get all 512 bytes on each recv but that's not true - you can and will get short reads. A little below you break out of the read loop if you haven't read exactly LENGTH (i.e. 512). That explains why your pgm quits after a couple of thousand bytes.
while ((fr_block_sz = recv(sd, revbuf, LENGTH, 0)) > 0) //LENGTH == 512
{
int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);
if (write_sz < fr_block_sz)
{
error("File write failed.\n");
}
bzero(revbuf, LENGTH);
if (fr_block_sz == 0 || fr_block_sz != 512)
{
break;
}
}
You want something more like this:
while ((fr_block_sz = recv(sd, revbuf, LENGTH, 0)) > 0) //LENGTH == 512
{
if (fr_block_sz < 0)
if (errno == EAGAIN)
continue;
else
error;
if (fr_block_sz == 0)
break; //done
int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);
if (write_sz < fr_block_sz)
{
error("File write failed.\n");
}
bzero(revbuf, LENGTH);
}

Resources