i have made one client server application in which client sends file (i.e ODT,PDF,MP3,MP4, etc) and server receives file.
i am dividing file in chunks and then transmits them in while loop.
below i have given main logic for both client and server.
when i do loop-back with 127.0.0.1, this code works successfully.
but when i runs client and server on two different PC, after transmitting a file client exits but server keeps receiving and then i have to press ctrl^C. the size of file at server side reaches over 1GB even if file size at client side is only around 4.2 MB.
and in loopback i am not getting such problem.
please tell me the needed corrections.
client.c
#define SIZE 512 // or anything else
char sendbuff[SIZE];
FILE *fr;
fr = fopen("1.mp3","r");
while(!feof(fr)){
count = fread(sendbuff, SIZE,1,fr);
count = send(clientsd, sendbuff,SIZE,0); //clientsd is socket descriptor.
}
send(clientsd, "xyz", 3, 0); //sending '1'. tells server, transmission is over now.
close(fr);
server.c
#define SIZE 512 // same as client side
char recvbuff[SIZE];
FILE *fw;
fw = fopen("2.mp3","w");
while(1){
count = recv(connsd, recvbuff, SIZE,0);
if(!strcmp(recvbuff,"xyz"))
break;
fwrite(recvbuff,SIZE, 1, fw);
memset(recvbuff,0,SIZE);
}
printf("Exit while\n");
fclose(fw);
any other simple and efficient way to do this ?
NOTE : I have changed my question. here some answers are on my old question where i have transmitted "1" instead of "xyz". which was an error.
The most obvious problem is your stop condition on the server side.
You assume that if the first byte received is '1' (0x31) than the transfer is over, but it might be a byte of the data (if the first byte of the chunk in the file is actually '1'). So you need some other way to signal the end of the file. One possibility is to use a wrapping for each packet sent, for example, before each packet send a specific value (for example '1') followed by the length, and when the transfer is complete send '0' to signal that the transfer is completed.
The other problems I can see are that:
You open the files as read text ("r") and write text ("w") which will stop processing if the EOF sequence appears in the middle of the file, instead you need to open them as read/write binary ("rb" / "wb" respectively).
You use chunks of 512 bytes, what if the file is not a multiple of 512 bytes?
Related
I want to send files asynchronously. I got on sending a file client->server->another client, but if i want to send a very big file, the client can't send any other commands to server until the file is totally sent. For every file client wants to send, i create a new thread in which i'll read 1kb of the file at a time and sending to the server, then the server will receive the 1kb and send further to the desired client. The problem is that when the client sends the file, the socket is full with bytes from server. I should make one client-server socket for every file i want to send? I've tried everything but nothing was a success.
Creating dedicated sockets for each transfer is one solution, and it's not a bad one unless the number of simultaneous connections is large (only so many IP ports are available on a system, and the server will need twice as many). Threads don't simplify this as much as you might think, and introduce their own challenges; select is a simpler way to efficiently transfer data on multiple sockets from a single thread/process. It works by exposing the underlying operating system's knowledge of which sockets are ready for reading and writing to the program.
The challenge for you with the multi-socket approach, regardless of threading choices, is that the server will have to tell the recipient to open a new connection back to the server for each new transfer. Now you need a command mechansim to tell the recipient to open a new connection for the next file.
Another option would be to open only one socket, but send multiple files simultaneously over the socket. You might accomplish this by sending a data structure containing the next parts of each file instead of simply streaming the file directly. For example, you might send a message that looks something like this (rendered in JSON for clarity, but it would be a valid transport format):
[
{
"name": "file.txt",
"bytes": "some smallish chunk of content",
"eof": false
},
{
"name": "another.txt",
"bytes": "chunk of another.txt content",
"eof": true
}
]
This example is of course naively simplistic, but hopefully it's enough to get the idea across: By structuring the messages you're sending, you can describe to which files, which chunks of bytes belong, and then send multiple chunks of multiple files at once. Because of your client->server->client approach, this seems like the best path forward to me.
using a struct similar to:
struct transferPacket
{
unsigned packetOfFile; // = 0 when starting a new file
unsigned fileNumber; // incremented with each new file
unsigned byteCount;
char payload[ MAX_PAYLOAD_LEN ];
};
When packetOfFile == 0 then starting a new file and payload contains filename
Otherwise indicates which part of file is being transfered.
When byteCount = 0 then EOF for that fileNumber
The above only takes a single TCP socket
multiple files can be transferred at one time.
The receiver knows which file the packet belongs to and which position in the file the payload belongs at.
The sender sends that same number of bytes each time, except for the first packet of a file and the EOF packet or the last data packet of the file
I'm trying to use openssl bio to perform FTP STOR operation. Most of the time it works perfectly, but sometimes it only sends partial data. So the logic goes like this:
1. authentication and passive mode selection
2. open data connection
3. write data
4. QUIT
All operations should be performed synchronously. The data writing function does this:
while (written < toWrite && n > 0) {
n = BIO_write(bio, message.c_str() + written, toWrite - written);
written += n;
}
After this loop, written == toWrite and n > 0, so it would indicate that the write was completed successfully. However, the file is truncated. When I view the operation in wireshark, I can notice that QUIT operation is sent right after the first chunk of data is transferred. Client also continues sending some data chunks after QUIT command. Does anyone have a clue how that is possible?
EDIT: If there's a short delay (e.g. sleep) between writing data and QUIT, it works perfectly.
I found out the problem. I did not wait for the response on control socket between closing the data connection and sending QUIT. This question was helpful for finding the answer.
New to Socket Programming. I was making a HTTP server. In the persistent connection, I keep the socket open after the server has sent the first file (1 MB text file) for the 1st HTTP request from the client. After that the server and client programs just sit idle. I have searched a lot and found that recv() keeps looking for data on the socket until the socket connection closes from the server side.
What Should I do in case of a persistent connection?
I am reading a file at the client side (File contains many lines. On each line there's just a file name, that is to be fetched from the server via a persistent connection)
Part of Server code which send the file requested:
while((bytesread = fread(filecontent,sizeof(char), 1024, fp))>0)
{
printf("Bytes Read:%d File Content:%s\n",bytesread,filecontent);
if((n = send(*newsockfd, filecontent, 1024,0))<0)
{
error("SERVER Error: Failed to Write File to Socket");
break;
}
bzero(filecontent,1024);
}
Part of client code where I read the file that has been sent by the server:
for(;;)
{
n=recv(socketfd, buffer, 1024,0);
printf("%d\n",n);
if(n>0)
{ printf("\n in while for reading the file for n bytes %d \n",n);
printf("Response:\n%s",buffer);
}
else if(n<0)
{
disperror("Error reading from socket");
}
if(n==0)
break;
}
Have spent a lot of time. Could not get what to do...
Your client-server protocol is insufficient. The server sends all the bytes of the input file (and more, because you hard-coded 1024 instead of using bytesread). But how should the client understand when the file is complete?
One easy solution is to have the server begin each transmission with the file size. You can simply send a uint64_t (not int because it must be a fixed size on all platforms). That number will represent the total bytes to follow (i.e. the file size). You can get the file size using fseek in the usual way (SEEK_END then ftell or similar).
Then, once your client has received the specified number of bytes, it can break out of the loop.
continues reading even though socket is empty
'Socket is empty' is meaningless. It is either open or closed. In this case it is still open, so your code keeps reading. It will only stop when the peer closes the connection.
If you're going to implement HTTP you need a good working knowledge of RFC 2616, especially the parts relating to content length. Your code doesn't begin to address that currently, and it's too brodpad a topic to cover here. Uffice it to say that keepalive and reading a socket to end of stream are mutually inconsistent.
NB if you get an error reading a socket other than EAGAIN/EWOULDBLOCK you should exit the loop, and you should also print the real error, not some message of your own devising.
NB (2) You don't need to zero the buffer.
NB (3) The correct way to print the buffer is printf("%.*s", n, buffer), but only if n > 0.
I am a C newbie learning sockets. I wrote a client-server program to receive a file and write it to another file.
The program itself works fine - the file is read by server properly and the client receives it in full, but the client does not exit after receiving all the data.
How would the client know when the entire file is received and how do I make it exit? Following is my client snippet.
Note: I added the condition while (data > 0) as a part of this attempt. Please correct this if wrong.
#define BUFFER 2048
char recived_data[BUFFER];
bzero(recived_data, BUFFER);
FILE *new_file = fopen(“Test.jpg”, “w”);
int data;
do {
data = recv(sockfd, recived_data, BUFFER, 0);
fwrite(recived_data, 1, sizeof(recived_data), new_file);
} while (data > 0);
Your server should close the socket after the whole file content has been sent. This would cause your recv function to return zero and end the client's receive loop.
If you want to keep the connection for some reason, then you would need to send some additional information to the client first (e.g. file length) - so the client knows when one file ends and (potentially) another begins. I'm not sure if you are interested in that, though.
The sender can send the file size before sending the file. The receiver can then receive the file size (say 4 bytes), then call recv() until the full file size has been received.
I'm so lost. I can't figure out how to stop reading from the server. I'm basically sending a list of every file in the directory from the server to the client. Heres what I'm doing.
SERVER SIDE:
struct dirent *ep = readdir(dp);
while( ep ){
sprintf(buf, "%s", (ep->d_name));
n = write(newsock, buf, MAX );
ep = readdir(dp);
}
CLIENT SIDE:
while( n = read(sock, buf, MAX)){
printf("buf: %s\n" , buf);
}
So the server side stuff works fine. I can see I'm sending all the file names right, but on the client side it reads all the names but just sits waiting to read more.
You either need to send some "EOF" indicator from the server so the client knows to break the loop, or have the server close the socket (after allowing 'some time' for the client to read all the data). This will cause the read to exit with an error condition.
Second is easier on the face of it, first is likely to be more reliable and efficient. Congratulations, you have now built your first communications protocol.
Define a protocol.
A very simple one might be to let the server send an empty (0-length) file name to the client to tell the client that it's done with sending. To successfully do so you might like to delimit each file name by for example an addtionaly \r\n sequence, or similar.