I am having trouble sending and receiving files while working with sockets in C.
Let's say I have a file that is 2,463 bytes big and I want to send it from client to server but it never sends the entire file.
I've been searching the internet for a while now but couldn't find a solution so I'd be very glad if someone could tell me how to make this work.
Here is my code:
Client:
char buffer[256];
bzero(buffer, 256);
int block_size;
while(1){
block_size = fread(buffer, sizeof(char), sizeof(buffer), fs); // read from the file
if (block_size == 0){
break;
}
if (block_size < 0){
perror("ERROR: Failed while sending data.");
exit(EXIT_FAILURE);
break;
}
void *p = buffer;
while (block_size > 0) {
int bytes_written = write(clientSocket, buffer, block_size); // send the data to server
if (bytes_written <= 0) {
perror("ERROR: Failed while sending data.");
exit(EXIT_FAILURE);
}
block_size -= bytes_written;
p += bytes_written;
}
bzero(buffer, 256);
}
Server:
bzero(buffer, 256);
int file_block_size = 0;
while (1){
bzero(buffer, 256);
file_block_size = read(incoming_socket, buffer,255); // read the data from client
fwrite(buffer, sizeof(char), file_block_size, fr); // write the data to file
if (file_block_size == 0 || file_block_size < 256){
fwrite(buffer, sizeof(char), file_block_size, fr);
break;
}
}
As I've said, this never sends the entire file that is for example 2,463 bytes big, only a portion of it.
Thanks in advance, will be glad for any help I can get.
You need to pair your read with a write. As in the current state your client code will send only the result of your last read operation since you are overwriting the contents of your buffer on each read.
Try something like this on the client side:
char buffer[256];
size_t bytes_read = 0;
ssize_t bytes_written = 0;
do{
bytes_read = fread(buffer, sizeof(char), sizeof(buffer), fs);
if(ferror(fs))
{
perror("Error while reading from file.");
close(clientSocket);
fclose(fs);
exit(EXIT_FAILURE);
}
bytes_written = write(clientSocket, buffer, bytes_read);
printf("Write operation status: %s; bytes sent: %d\n", strerror(errno), bytes_written);
} while(!feof(fs) && bytes_written != -1);
And on the server side I would do:
char buffer[256];
ssize_t bytes_read = 0;
while((bytes_read = read(incoming_socket, buffer, sizeof(buffer))) > 0)
{
printf("%d bytes read\n", bytes_read);
fwrite(buffer, sizeof(char), bytes_read, fr);
if(ferror(fr))
{
perror("Error while writing to file");
close(incoming_socket);
fclose(fr);
exit(EXIT_FAILURE);
}
}
if(bytes_read == -1)
printf("%s\n", strerror(errno));
Related
EDIT: Im trying to send a file from the server to the client. When I send a file of 44 bytes, the client reads in 256 bytes on the first iteration (which is the size of char array buf) and on the next iteration reads the remaining 44 bytes. Why does it not read the 44 bytes initially?
Client snippet ( receives file ):
while((bytes_read = read(sd, buf, sizeof(buf))) > 0){ //receving file contents and writing to file
printf("DEBUG B: read=%zd\n", bytes_read);
fwrite(buf, 1, bytes_read, fp);
total_bytes_read += bytes_read;
printf("DEBUG C: total=%zu\n", total_bytes_read);
if(ferror(fp)){
perror("Error when writing to file\n");
exit(1);
fclose(fp);
}
//printf("Filesize is: %zu \n", filesize);
if(total_bytes_read == filesize){
break;
}
}
printf("The client has received the file\n");
}
server part(sends file):
strcpy(buf, "no issues");
if((y = write(sd, buf, sizeof(buf))) < 0){
perror("Error reporting back to client\n");
}
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
fseek(fp, 0, SEEK_SET);
printf("Sending file size\n");
if((write(sd, &filesize, sizeof(filesize))) < 0){ //sending filesize
printf("error sending file size\n");
}
printf("Filesize is: %zu \n", filesize);
printf("Sending file\n");
while((bytes_read = fread(buf, 1, sizeof(buf), fp)) > 0){ //sending file contents
printf("DEBUG A: Bytes read %zu \n", bytes_read);
if ((bytes_written = write(sd, buf, bytes_read)) < 0){
printf("Error sending server file.\n");
}
printf("DEBUG B: Bytes sent %zu \n", bytes_written);
total_bytes_sent += bytes_written;
printf("Total bytes sent %zi \n", total_bytes_sent);
}
printf("File has been sent\n");
fclose(fp);
}
If more code is required I will post it, let me know. Greatly appreciate any help!
I am having trouble transferring files through TCP sockets in C. I send the files in little chunks of 8192 bytes from a server to a client. The issue is that the client receives the one before last incompletely and does not receive the last one at all.
Here are both relevant parts of the code.
server:
fd = open(filename,O_RDONLY);
if (fd == -1)
{
fprintf(stderr, "Error opening file --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
/* Get file stats */
if (fstat(fd, &file_stat) < 0)
{
fprintf(stderr, "Error fstat --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stdout, "File Size: \n%d bytes\n", file_stat.st_size);
sprintf(file_size, "%d", file_stat.st_size);
/* Sending file size */
len = send(peer_socket, file_size, sizeof(file_size), 0);
if (len < 0)
{
fprintf(stderr, "Error on sending greetings --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stdout, "Server sent %d bytes for the size\n", len);
offset = 0;
remain_data = file_stat.st_size;
/* Sending file data */
while(((sent_bytes = sendfile(peer_socket, fd,&offset, BUFSIZ))>0)&&(remain_data > 0))
{
remain_data -= sent_bytes;
fprintf(stdout, "2. Server sent %d bytes from file's data, offset is now : %d and remaining data = %d\n", sent_bytes, offset, remain_data);
}
and client side:
ecv(client_socket, buffer, BUFSIZ, 0);
file_size = atoi(buffer);
fprintf(stdout, "\nFile size : %d\n", file_size);
//received_file = fclose(fopen(FILENAME, "w"));
received_file = fopen(FILENAME, "w");
if (received_file == NULL)
{
fprintf(stderr, "Failed to open file --> %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
remain_data = file_size;
while ((remain_data > 0)&&((len = recv(client_socket, buffer, BUFSIZ, 0)) > 0))
{
fwrite(buffer, sizeof(char), len, received_file);
remain_data -= len;
//if (remain_data < BUFSIZ)
// buffsize = remain_data;
//bzero(buffer,BUFSIZ);
//if (len == 0 || len != BUFSIZ)
// break;
fprintf(stdout, "Received %d bytes , %d bytes remaining\n", len, remain_data);
}
//code for accelerator here
fclose(received_file);
The output on server side looks like this (which seems to be correct):
But on the client side this is what I get:
From there the applications on both sides are stuck forever. Any idea what might cause the trouble?
Thanks for your answers
it works only when i do it with my own Computer , but when i use another Computer the file recieved is a mess and the size is always another.
Server:
while (1) {
ZeroMemory(r_buf, MAX_BUFF_RECV - 1);
bytesReceived = recv(sock, r_buf, FILE_DOWNLOAD_SIZE, 0);
if (bytesReceived < 0) {
// ERROR
puts("[!] recv failed");
return;
}
else if (bytesReceived < FILE_DOWNLOAD_SIZE) {
// LAST CHUNCK
if (WriteFile(out, r_buf, bytesReceived, &n, NULL) == FALSE) {
printf("WriteFile() error %d\n", GetLastError());
}
break;
}
else {
if (WriteFile(out, r_buf, bytesReceived, &n, NULL) == FALSE) {
printf("WriteFile() error %d\n", GetLastError());
}
}
}
Client:
while (1)
{
ZeroMemory(buff, FILE_DOWNLOAD_SIZE);
nread = fread(buff, 1, FILE_DOWNLOAD_SIZE, f);
if (nread != FILE_DOWNLOAD_SIZE) {
send(s, buff, nread, 0);
break;
}
else {
send(s, buff, nread, 0);
}
}
im for hours on it , pls tell me whats wrong
In connection-oriented transports, like TCP, send() and recv() are not 1-to-1. There is no guarantee that what you send() will be transmitted in a single data packet, or that recv() will receive everything that you send() in a single go.
There is no guarantee that send() will even accept everything that you give it. It will copy whatever it can into the socket's outbound buffer and return the actual number of bytes copied. So it can accept fewer bytes than requested.
Likewise, recv() will copy whatever data is currently available in the socket's inbound buffer, at least 1 byte but not more than the specified number of bytes, into your specified buffer and will return the actual number of bytes copied. So it can receive fewer bytes than requested.
You also need to know how much file data is actually being transmitted so you know when to stop reading the data. Since recv() can return fewer bytes than requested, you cannot rely on buffer sizes alone to indicate EOF.
You are not taking any of this into account in your code.
Try something more like this instead:
Server:
bool readRaw(SOCKET sock, void *buf, int bufSize)
{
char *pbuf = (char*) buf;
while (bufSize > 0)
{
int bytesReceived = recv(sock, pbuf, bufSize, 0);
if (bytesReceived < 0)
{
printf("[!] recv() error %d\n", WSAGetLastError());
return false;
}
else if (bytesReceived == 0)
{
puts("[!] client disconnected");
return false;
}
else
{
pBuf += bytesReceived;
bufSize -= bytesReceived;
}
}
return true;
}
...
unsigned __int64 fileSize = 0;
if (readRaw(sock, &fileSize, sizeof(fileSize)))
{
while (fileSize > 0)
{
int bufSize = min(fileSize, MAX_BUFF_RECV);
if (!readRaw(sock, r_buf, bufSize))
break;
if (!WriteFile(out, r_buf, bufSize, &n, NULL))
{
printf("[!] WriteFile() error %d\n", GetLastError());
break;
}
fileSize -= bufSize;
}
}
Client:
bool sendRaw(SOCKET sock, void *buf, int bufSize)
{
char *pbuf = (char*) buf;
while (bufSize > 0)
{
int bytesSent = send(sock, pbuf, bufSize, 0);
if (bytesSent < 0)
{
printf("[!] send() error %d\n", WSAGetLastError());
return false;
}
else
{
pBuf += bytesSent;
bufSize -= bytesSent;
}
}
return true;
}
...
fseek(f, 0, SEEK_END);
long int pos = ftell(f);
fseek(f, 0, SEEK_SET);
if (pos == -1)
printf("[!] ftell() error\n");
else
{
unsigned __int64 fileSize = pos;
if (sendRaw(s, &fileSize, sizeof(fileSize)))
{
while (fileSize > 0)
{
int bufSize = min(FILE_DOWNLOAD_SIZE, fileSize);
nread = fread(buff, 1, bufSize, f);
if (nread == 0)
{
printf("[!] fread() error\n");
break;
}
if (!sendRaw(s, buff, nread))
break;
uifileSize -= nread;
}
}
}
I am attempting to make a simple server so that two clients can communicate with each other. The main server code accepts the two client connections and then forks off a process that uses execl to generate a personal server between the two clients so that the main server can continue looking for new connections. Everything seems to work correctly until the personal server attempts to contact the clients and they both receive gibberish, if anyone knows what could cause this please let me know.
Main server after accepting two clients:
if(fork() == 0){
close(listener);
int nBytes;
char* playerOne[20];
char* playerTwo[20];
//Creates strings to hold file descriptor information for execl
char connAscii[sizeof(int)];
char connAscii2[sizeof(int)];
snprintf(connAscii,sizeof(conn), "%d", conn);
snprintf(connAscii2,sizeof(conn2), "%d", conn2);
fprintf(stderr, "Int conn: %d, asciiConn: %s, backToInt: %d\n", conn, connAscii, atoi(connAscii));
char *argf[2];
argf[0] = connAscii;
argf[1] = connAscii2;
fprintf(stderr, "that is to say %s and %s\n", argf[0], argf[1]);
//Send Handle Request to Connection 1
nBytes = send(conn, handleRequest, sizeof(handleRequest),0);
if(nBytes == -1){
perror("send");
exit(1);
}
//Receive Handle from Connection 1
nBytes = recv(conn, playerOne, 20, 0);
if(nBytes == -1){
perror("recv");
exit(1);
}
//Send Handle Request to Connection 2
nBytes = send(conn2, handleRequest, sizeof(handleRequest),0);
if(nBytes == -1){
perror("send");
exit(1);
}
//Receive Handle from Connection 2
nBytes = recv(conn2, playerTwo, 20, 0);
if(nBytes == -1){
perror("recv");
exit(1);
}
//Send Handle for Connection 2 to Connection 1
nBytes = send(conn, playerTwo, sizeof(playerTwo),0);
if(nBytes == -1){
perror("send");
exit(1);
}
//Send Handle for Connection 1 to Connection 2
nBytes = send(conn2, playerOne, sizeof(playerOne),0);
if(nBytes == -1){
perror("send");
exit(1);
}
//Passes file descriptors to privateServer
execl("privateServer","privateServer", connAscii, connAscii2, (char *)0);
}
Personal server invoked by execl:
char greet[] = {"Hello players, please wait for match setup."};
int main(int argc, char *argv[]) {
int conn1 = atoi(argv[1]);
int conn2 = atoi(argv[2]);
int sent;
fprintf(stderr, "Attempting connection with %d\n", conn1);
sent = send(conn1, greet,sizeof(greet),0);
if(sent == -1){
perror("send");
exit(1);
}
sent = send(conn2, greet,sizeof(greet),0);
if(sent == -1){
perror("send");
exit(1);
}
fprintf(stderr,"Hopefully they got it\n");
return 0;
}
Clients: Reading the recv buff char by char results in gibberish and printing the entire buffer doesn't show anything, but numbytes == 61.
char *buff = (char*)malloc(100);
memset(&buff[0],0,sizeof(buff));
numbytes = recv(sockfd, buff, 99, 0); //should be from private server
if (numbytes == -1) {
perror("recv");
exit(1);
}
buff[numbytes] = '\0';
int i;
for(i = 0; i < numbytes; i++){
fprintf(stderr, "%c", buff[i]);
}
printf("From match server: %.*s (%d bytes)\n", numbytes, buff, numbytes);
There are several errors:
char* playerOne[20];
char* playerTwo[20];
You want an array of chars, not an array of pointers to chars
change to
char playerOne[20];
char playerTwo[20];
And here:
char *buff = (char*)malloc(100);
memset(&buff[0],0,sizeof(buff));
sizeof(buff) is the size of a pointer to char, change to
memset(&buff[0],0,100);
As pointed out by #user3629249, don't use magic numbers like 100, instead
#define MAX_BUFF 100
char *buff = malloc(MAX_BUFF);
memset(&buff[0],0,MAX_BUFF);
But there is no need to memset if you are null-terminating the string.
I want to send file through socket and after that i want to send three messages. This code below works, but i have to send first sentence two times. My question is why? Without one sentence1, receiver display sentence2, sentence3 and sentence3. What is wrong with this code?
I'm using tcp protocol.
Sender.c
char file_size[256];
struct stat file_stat;
int sent_bytes = 0;
int fd;
int offset;
int remain_data;
fd = open(FILE_TO_SEND, O_RDONLY);
if (fd == -1)
{
fprintf(stderr, "Error opening file --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
/* Get file stats */
if (fstat(fd, &file_stat) < 0)
{
fprintf(stderr, "Error fstat --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stdout, "File Size: \n%d bytes\n", file_stat.st_size);
sprintf(file_size, "%d", file_stat.st_size);
write(sck, file_size, 256);
char buffer[1024] = "";
while (1) {
int bytes_read = read(fd, buffer, sizeof(buffer));
if (bytes_read == 0)
break;
void *p = buffer;
while (bytes_read > 0) {
int bytes_written = write(sck, p, bytes_read);
if (bytes_written <= 0) {
// handle errors
}
bytes_read -= bytes_written;
p += bytes_written;
}
}
char sentence[1024];
write(sck, sentence1, 1024);
write(sck, sentence1, 1024);
write(sck, sentence2, 1024);
write(sck, sentence3, 1024);
Receiver.c
char buffer[1024] = "";
int sck = *((int*) arg);
int file_size;
read(sck, buffer, 256);
file_size = atoi(buffer);
ssize_t len;
FILE *received_file;
int remain_data = 0;
received_file = fopen("plik.pdf", "w");
if (received_file == NULL)
{
fprintf(stderr, "Failed to open file foo --> %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
remain_data = file_size;
while (((len = recv(sck, buffer, 1024, 0)) > 0) && (remain_data > 0))
{
fwrite(buffer, sizeof(char), len, received_file);
remain_data -= len;
}
fclose(received_file);
read (sck, buffer, 1024);
printf("%s 1\n", buffer);
read (sck, buffer, 1024);
printf("%s 2\n", buffer);
read (sck, buffer, 1024);
printf("%s 3\n", buffer);
Nothing to do with TCP protocol. Your logic is flawed. You are receiving the data and then checking for remain_data. So your sentence1 is received and discarded in the while loop.
Move your recv() into the body of while to fix this or change the order in while.
while ((remain_data > 0) && ((len = recv(sck, buffer, 1024, 0)) > 0))
In the modified while, you call recv() only if remain_data > 0. recv() is not called if remain_data == 0 (lazy evaluation). So your while loop ends immediately after receiving the file and ready to receive your sentences. In your code, the while loop read the first sentence, then checked remain_data > 0 effectively discarding sentence1