This is the snippet of client code:
connect(DescrittoreClient, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
strcpy(Buffer, filename);
send(DescrittoreClient, Buffer, strlen(Buffer), 0);
fd = open(filename, O_CREAT | O_WRONLY,0644);
while ((nread = read(DescrittoreClient, Buffer, sizeof(Buffer))) != 0) {
write(fd, Buffer, nread);
memset(Buffer,0,sizeof(Buffer));
}
int gg;
while( (gg = recv(DescrittoreClient, Buffer, sizeof(Buffer), 0)) == -1) continue;
printf("%d\n", gg);
printf("Risposta del server: %s\n", Buffer);
close(DescrittoreClient);
return EXIT_SUCCESS;
And this is the snippet of the server code:
while(1){
rc = recv(DescrittoreClient, filename, sizeof(filename), 0);
fd = open(filename, O_RDONLY);
fstat(fd, &stat_buf);
offset = 0;
rc = sendfile(DescrittoreClient, fd, &offset, stat_buf.st_size);
if (rc != stat_buf.st_size) {
fprintf(stderr, "incomplete transfer from sendfile: %d of %d bytes\n", rc, (int)stat_buf.st_size);
exit(1);
}
strcpy(Buffer, "Dati inviati correttamente");
if( (send(DescrittoreClient, Buffer, strlen(Buffer), 0)) == -1){
printf("Errore nell'invio della stringa\n");
close(DescrittoreClient);
close(fd);
exit(1);
}
}
close(DescrittoreServer);
return EXIT_SUCCESS;
This is the expected behaviour:
Client --Give me file X--> Server
Server --send the file X--> Client
Server -->send string "File has been sent"--> Client
But this is the real behaviour:
Client --Give me file X--> Server
Server --send the file X--> Client
Server -->_NOTHING_--> Client
So the problem is that the client doesn't receive "File has been sent". I've checked if the problem is server's side but it isn't (in fact the server send the string)
(based on the comments above) -- the thing to realize is that TCP communication is 100% stream based, with no built-in framing. That means that all the TCP layer does is make sure that the receiver receives the bytes in the same order that the sender sent them -- but it does not guarantee that the bytes will be received in the same intervals as they were sent. (For example, if you send() 10 bytes, then 20 bytes, then 50 bytes, the receiver might receive all 80 bytes at once, or 63 bytes followed 17 bytes, or any other combination of recv()s that sum up to 80 bytes total).
Therefore in order to send multiple separate items in such a way that the receiver can interpret them correctly, you need to define your own rules for framing the data. In your case you need to send n bytes of file data, followed by a string, and what your receiving program needs to know is how many bytes of file data to expect. That way, once it has received (that many) bytes, it knows the remaining bytes are string data and won't just write them to the file.
My suggestion would be to send the file's size first (either as a 4-byte integer, or an 8-byte long if you need to support file sizes greater than 4 gigabytes). Then the receiving code would be like this:
Receive 4 bytes
Interpret those four bytes as an integer (you may want to pass this value through htonl() on the sender and ntohl() on the receiver, in order to avoid possible endian-ness issues here)
Receive N bytes and write them to the file
Receive any remaining bytes as a string.
Related
I'm making a TCP socket programming.
client:
a client will receive a list of files from a server --> send a file name to the server --> receive the file from the server
My problems:
the server sends the list of files correctly. I printed out all and all of them are sent well. however, the client receives it well but while the loop isn't finished even if the server sending while loop is finished.
[client]
while ((read_cnt=read(sd, buf, BUF_SIZE)) != 0) {
read_cnt=read(sd, buf, BUF_SIZE);
printf("%s\n", buf);
}
[server]
while ((entry=readdir(dir)) != NULL) {
sprintf(buf, "%s\n", entry->d_name);
write(clnt_sd, buf, strlen(buf));
}
the server sends 17 messages but the client receives 15 messages and while loop is not finished. when while loop receives "finish", make client finishes the while loop --> still it receives 15 messages even if the server sent 17 messages.
[client]
while (1) {
read_cnt=read(sd, buf, BUF_SIZE);
fwrite((void*)buf, 1, read_cnt, fp);
printf("%s\n", buf);
if (strstr(buf, "fin") != NULL) {
break;
}
total_read += read_cnt;
pcnt = ((total_read/ file_size) * 100.0)/10;
printf("(%.0d %%) Send %.0f / %.0f bytes.\n", pcnt*10, total_read, file_size);
}
[server]
FILE *fp;
fp = fopen(file_name, "r");
if (fp == NULL) {
printf("File not Exist");
exit(1);
}
fseek(fp, 0, SEEK_END);
int file_size = ftell(fp);
sprintf(buf, "%d", file_size);
write(clnt_sd, buf, read_cnt);
fseek(fp, 0, SEEK_SET);
while (feof(fp) == 0) {
read_cnt = fread((void*)buf, 1, BUF_SIZE, fp);
write(clnt_sd, buf, read_cnt);
}
fclose(fp);
I tried memset, bzero to make buffer empty but it didn't work.
I think the problem is the client part because when I checked server side by using print, they are sending well and finished the while loops. But I don't know what's the problem in receiving process on the client side. Please, Let me know what's the problem is.
the server sends 17 messages but the client receives 15 messages
Completely normal.
TCP is a stream protocol, not a message passing protocol. What you "send" on one side may not be the exact number of bytes received at the other end. You have to expect messages to arrive chunked, coalesced, or segmented between and within read/recv calls. You can't even assume that the initial "size" write you send as a 4-byte message is received within the same read call either as an entire message.
Implement your client side code to expect read and recv to return a random number of bytes up to the size of the buffer you pass in. If you get less bytes than expected, you need to make another read/recv call to receive the rest - adjusting your destination buffer pointer as needed. Or use the MSG_WAITALL flag with recv (instead of read) to get all the data in one call. You still need to check the result of the buffer to make sure you got the expected number of bytes, that the stream didn't close, and to validate that an error (-1 return) didn't occur.
EDIT: Changed the while loop condition from > 0 to !=0. There are also 2 or more newlines being output on the terminal after printing the content, but in the file there aren't.
I'm doing a file transfer from the client to the server. The contents are transferred successfully, but when receiving it doesn't exit the while loop. Is my while condition somehow wrong? After I force stop the program, i can see that the file has actually been copied successfully, it just does not exit this while loop after writing everything to the file.
This is the code where I'm having trouble:
ssize_t bytes_read = 0;
int error;
while((bytes_read = read(sd, buf, sizeof(buf))) != 0){
printf("writing: %s\n", buf);
if((error = fwrite(buf, 1, bytes_read, fp)) < 0)
{
printf("error");
}
if((bytes_read = read(sd, buf, sizeof(buf))) < 0){
break;
}
}
Tried to keep it as minimal as possible, as I'm sure there's something very simplistically wrong here.
EDIT: I tried it with a larger file, and it seems that its missing some content here and there but not in a consistent pattern.
EDIT: Here is the client side.
else if(strcmp(shortCommand, "put") == 0){
char *tmp = buf + 4;
char filename[MAX_BLOCK_SIZE];
strcpy(filename, "filename ");
strcat(filename, tmp);
FILE *fp;
printf("File name: %s\n", tmp);
fp = fopen(tmp, "rb");
if(fp == NULL){
printf("ERROR: Requested file does not exist.\n");
}
else{
printf("Client sending filename...\n");
if ((nw = write(sd, buf, sizeof(buf))) < 0){ //sending the file name to the client first
printf("Error sending client's filename.\n");
}
printf("Client sending file...\n");
size_t bytes_read = 0;
ssize_t bytes_written = 0;
while((bytes_read = fread(buf, 1, sizeof(buf), fp)) != 0){ //sending the file contents
if ((bytes_written = write(sd, buf, bytes_read)) < 0){
printf("Error sending client file.\n");
}
}
fclose(fp);
}
}
The server code assumes that it will observe read() to return 0 after it reads all the data that the client transfers, but that will not happen just because the client stops sending data. read() returns 0 to indicate that the end of the file has been reached, but "file" in that sense means the read side of its socket. Until the client closes the peer socket, the server will not perceive EOF on its socket. And that's perfectly reasonable because until then, the client might send more data, proving that indeed EOF had not previously been reached. Therefore, if the server tries to perform a (blocking) read on the socket after receiving all the data then it will block until the client sends more or closes the connection, or until it detects an error, is interrupted by a signal, etc..
If the client doesn't actually intend to send any further data after the file content then it should close() that socket after sending all the bytes of the file content, or at least shutdown() the write side.
If, on the other hand, the client is keeping the socket open because it intends to send more data later, then you need a new strategy. In that case the end of the file content does not coincide with the logical end of the stream, and you therefore need a different mechanism to communicate to the server where the end of the file data is. This is where communication protocols such as HTTP come in, but for your purpose, you don't need a protocol nearly as complicated as HTTP.
It might suffice, say, for the client to send data to the server as one or more chunks, each comprising a byte count followed by the specified number of bytes of content. You could insist that the whole file content always go into one chunk, but if you want to allow splitting the file into multiple chunks then you could use a chunk length of zero to signal the end of the data.
I've seen a lot of questions related to what I'm trying to do but I haven't been able to get any solution to work for me as yet.
I'm try to write two socket programs (one client and one server) so that the server is able to send files of any type (by bytes) to the client. I'm not sure how to construct/coordinate the following:
(in the server) the read statement(s) to get data from the file (I'm using fread())
(in the server) the write statement(s) to send the data to the client (I'm using write())
(in the client) the read statement(s) to receive data from the server (I'm using read())
(in the client) the write statement(s) to write the data received from the server to a file (I'm using fwrite())
I want to transmit the data in chunks of bytes. Will one fread() statement and one write() statement in the server be sufficient regardless of how large the file is? (or does that depend on the size of my buffer?)
On the client side, will one call to read() and one call to fwrite() be enough? (or does that depend on the size of my buffer?)
I'm new to Socket Programming. Thanks in advance!
Parts of my server and client below:
Client Side:
/*try to get file from server*/
char receive_buffer[256];
FILE * new_file;
int bytes_received = 0;
new_file = fopen("newfile.txt", "w");
bytes_received = read(conn_s, receive_buffer, 256);
printf("Received %d bytes\n", bytes_received);
while( bytes_received > 0)
{
bytes_received = read(conn_s, receive_buffer, 256);
printf("Received %d bytes\n", bytes_received);
fwrite(receive_buffer, 1, bytes_received, new_file);
printf("writing bytes!\n");
break;
}
if(bytes_received < 0)
{
printf("/nError reading bytes of data/n");
}
Parts of the server code:
FILE * file_to_get = fopen("sample.txt", "rb");
if(file_to_get == NULL)
{
printf("No such file!");
exit(0);
}
while(1)
{
unsigned char buff[256];
int num_read = fread(buff, 1, 256, file_to_get);
printf("read %d bytes\n", num_read);
if(num_read > 0)
{
write(conn_s, buff, num_read);
printf("writing %d bytes\n", num_read);
}
if(num_read < 256)
{
if(feof(file_to_get))
printf("End of file\n");
if(ferror(file_to_get))
printf("Error reading bytes\n");
break;
}
}
When sending to the network, you can use a single call to write(). If there's not enough buffer space in the kernel for the whole thing, write() will block until it's able to process all of it. You can also write it in chunks, that's fine as well. It doesn't really matter.
When reading from the network, you have to call read() in a loop. The buffer size you specify when calling read() is just the maximum it's allowed to return, it won't wait for that much to be received. So it can (and often does) return less than this. Just keep calling read() until it returns 0 to indicate EOF, writing each buffer to the file.
I am writing a simple client/server application and I ran into a very weird issue.
I am trying to send a .zip file to the client and some more data after that.
Sending the .zip works fine, the server writes to the socket, the client reads from the socket, just as intended.
The problem is right after that.
The server runs fine and keeps writing to the socket, but the client just won't read anything. It gets stuck on the very next read() call, no matter what I try to send.
I've checked to see if the socket descriptors are alright, and they are. I also thought that maybe there is not enough data in the socket for the client to read, but there definitely is.
I also tried doing the same write/read before and after sending that .zip file: it works fine before, but client doesn't see it after sending that .zip.
I am out of ideas.
Here's the function I use to send the .zip:
typedef struct thData{
int idThread; //thread ID
int cl; //client descriptor
}thData;
void send_info(struct thData tdL)
{
char file_path[256]="v1.zip";
char sd_buffer[256];
bzero(sd_buffer, 256);
FILE *fd = fopen(file_path, "rb");
if(fd == NULL)
{
printf("ERROR: %s not found.\n", file_path);
exit(1);
}
int read_size;
int write_size;
while((read_size = fread(sd_buffer, sizeof(char), 256, fd)) > 0)
{
if((write_size=write(tdL.cl, sd_buffer, read_size)) < 0)
{
perror("ERROR: writing to client: \n");
break;
}
bzero(sd_buffer, 256);
}
}
And what I use to receive the .zip:
void receive_info(int sd) //sd being the socket descriptor
{
char* file_path = "subject.zip";
char received_buffer[256];
int total_received=0;
int total_wrote=0;
FILE *fd = fopen(file_path, "wb");
if(fd == NULL)
printf("Cannot open %s\n", file_path);
else
{
bzero(received_buffer, 256);
int read_size = 0;
while((read_size = read(sd, received_buffer, 256)) > 0)
{
total_received=total_received+read_size;
int write_size = fwrite(received_buffer, sizeof(char), read_size, fd);
total_wrote=total_wrote+read_size;
if(write_size < read_size)
{
perror("ERROR: \n");
}
bzero(received_buffer, 256);
if (read_size == 0 || read_size != 256)
{
break;
}
}
if(read_size < 0)
{
perror("ERROR: reading: ");
exit(1);
}
fclose(fd);
}
}
Any help would be greatly appreciated.
I think that the problem is that you are reading too much.
In TCP there are no boundaries in the packets sent from one peer to the other. It is just a stream of bytes, and the pieces received from recv/read() bear no relation (in principle) to the pieces sent from send/write().
Now, imagine that your ZIP file is 300 bytes long, and your extra data is 10 bytes long. Your sender code will do:
write 256 bytes (first piece from ZIP).
write 44 bytes (last piece from ZIP).
write 10 bytes (the extra data).
And your receiver code will do:
read 256, get 256 bytes (first piece from ZIP).
read 256, get 54 bytes (last piece from ZIP plus the extra data).
read XXX bytes, wait forever!
If you look carefully to the ZIP files you'll probably see those extra bytes at the end of subject.zip.
The solution, if you don't want to close and open another socket, is to make the protocol a bit more complicated. For example, you could send a structure before the file (a header) that includes the size of the file. That way the receiver will know when to stop reading.
PS: Note that your code has a few risky edges. For example, write() might not write all the given bytes, but you are not checking that; you are not closing the file...
PS2: I find curious that you feel the need to write sizeof(char) instead of just 1 but you write 256 instead of sizeof(sd_buffer).
I'm writing a toy client/server app and sending data over a UDP stream. Everything is working well when I send small messages like "test" or something like that. But when I go to transfer files, I seem to be transferring too much data.
The file that I am transferring is a little less than 4k in size (at least according to an ls command). But when my sendto operation completes, my confirmation message shows that I have sent exactly 5000 bytes (which is the max size of my buffer).
I'd rather not break the sendto up if I don't need to since UDP can potentially transfer messages out of order. Anyone see what I am doing wrong? I think that is has to do with my use of sizeof(buffer), but I don't know how to transfer exactly the number of bytes that I want. Thank you!
Here is the relevant part of the code. Please let me know if you need more:
char buffer[5000];
char path[] = "myfile";
FILE* fp;
if ((fp = fopen(path, "rb")) == NULL) {
printf(stdout, "Error opening the file: %s\n", strerror(errno));
exit(1);
}
memset(&buffer[0], 0, sizeof(buffer));
do {
fread(buffer, 1, MAXBUFSIZE, fp);
} while (!feof(fp));
if ( (numbytes = sendto(sockfd, buffer, sizeof(buffer), 0,
(struct sockaddr *)&server_addr, sizeof(server_addr))) < 0)
{
perror("send error");
}
fprintf(stderr, "client sent %d bytes to server\n", numbytes);
As per the sendto command, UDP will send the same amount of data as specified in the send length; the third param is the send length: http://linux.die.net/man/2/sendto . The example is specifying sizeof(buffer) as the send length and sizeof(buffer) is 5000. Accordingly, UDP sends 5000 bytes from the buffer (which is actually the entire buffer). If we want to send the exact number of bytes as present in the file, then we should read the number of bytes in the file, and pass that as the send length.
numbytes = sendto(sockfd, buffer, sizeof(buffer), 0,