c socket send file size and then the file - c

This is a snippet of client.c:
size_t fsize;
int total_bytes_read = 0, ret_val;
hp = gethostbyname(argv[1]);
DescrittoreClient = socket(AF_INET, SOCK_STREAM, 0);
connect(DescrittoreClient, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
strcpy(Buffer, filename);
send(DescrittoreClient, Buffer, strlen(Buffer), 0);
ret_val = read(DescrittoreClient, &fsize, sizeof(fsize));
if(ret_val == -1){
printf("Errore durante ricezione grandezza file\n");
close(DescrittoreClient);
exit(1);
}
fd = open(filename, O_CREAT | O_WRONLY,0644);
if (fd < 0) {
perror("open");
exit(1);
}
while(total_bytes_read < fsize){
while ((nread = read(DescrittoreClient, Buffer, sizeof(Buffer))) > 0){
write(fd, Buffer, nread);
total_bytes_read += nread;
}
}
printf("File ricevuto\n");
And this is a snippet of server.c:
int DescrittoreServer, DescrittoreClient, LunghezzaClient;
int NumPorta = atoi(argv[1]);
char Buffer[1024] = {};
int rc, fd;
off_t offset = 0;
struct stat stat_buf;
char filename[1024] = {};
int fsize[10240] = {};
DescrittoreServer = socket(AF_INET, SOCK_STREAM, 0);
if(bind(DescrittoreServer, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){
perror("Errore di bind\n");
close(DescrittoreServer);
exit(1);
}
listen(DescrittoreServer, 5);
LunghezzaClient = sizeof(cli_addr);
while(1){
DescrittoreClient = accept(DescrittoreServer, (struct sockaddr *) &cli_addr, &LunghezzaClient);
rc = recv(DescrittoreClient, filename, sizeof(filename), 0);
fprintf(stderr, "Ricevuta richiesta di inviare il file: '%s'\n", filename);
/* open the file to be sent */
fd = open(filename, O_RDONLY);
/* get the size of the file to be sent */
fstat(fd, &stat_buf);
*fsize = stat_buf.st_size;
send(DescrittoreClient, fsize, sizeof(fsize), 0);
/* copy file using sendfile */
offset = 0;
rc = sendfile(DescrittoreClient, fd, &offset, stat_buf.st_size);
if (rc != stat_buf.st_size) {
fprintf(stderr, "Trasferimento incompleto: %d di %d bytes\n", rc, (int)stat_buf.st_size);
exit(1);
}
close(DescrittoreClient);
close(fd);
}
What does this code do:
1) client sends the name of a file
2) server sends the length (in byte) of the file
3) client receives the length of the file
4) server sends the file
5) client receives the file
The problem is that the file is not entirely received but only a part of it is written by the client (for example a file of 2143 byte is sent by the server and only 95 byte are received by the client) and i don't understand why!
PS: some errors handling have been deleted so the code is more readable!

You have to call recv() in a loop and sum up it's return values:
while (read_bytes < filesize) {
read_bytes += recv(socket, buffer + read_bytes, filesize-read_bytes, flags)
}
of course you should also add error handling, i.e., check if you read 0 bytes and the connection was closed.

The problem is that i have declared char nread=0 instead of int nread=0 into the client and so the maximum value i can read with char is 127...changed char to int solved my problem!

Related

Weird file output socket file transferring

So, I'm making a socket program to connect two programs and everything works thus far; setting up winsock, connecting and interaction. However, the file being sent over from the client side to the server side has weird characters in it.
Example:
File: test.txt
Contents: Hey, how are you?
** Client sends file over to Server **
Expected Output: Hey, how are you?
Actual Output: 7_ Ä _
Server code:
int main() {
WSADATA Winsock;
SOCKET Socket, Sub;
Addr addr;
IncomingAddress incomingAddress;
int AddressLen = sizeof(IncomingAddress);
// Start up Winsock
WSAStartup(MAKEWORD(2, 2), &Winsock);
if (LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2) {
WSACleanup();
return 0;
}
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// Memset alternative
ZeroMemory(&addr, sizeof(Addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(portNumber);
bind(Socket, (sockaddr*) &addr, sizeof(Addr));
if (listen(Socket, 1) == SOCKET_ERROR) {
printf("Listening error!\n");
} else {
printf("Listening...\n");
}
if (Sub = accept(Socket, (sockaddr*) &incomingAddress, &AddressLen)) {
int Size;
char *Filesize = malloc(MAX_PATH);
if (recv(Socket, Filesize, MAX_PATH, 0)) { // File Size
Size = atoi((const char*) Filesize);
printf("File size: %d\n", Size);
}
char *Buffer = malloc(Size);
int Offset = 0;
while (Size > Offset) {
printf("TESST");
int Amount = recv(Socket, Buffer + Offset, Size - Offset, 0);
if (Amount <= 0) {
printf("Error: " + WSAGetLastError());
break;
} else {
Offset += Amount;
}
}
FILE *File;
File = fopen("test.txt", "wb+");
fwrite(Buffer, 1, Size, File);
fclose(File);
getchar();
closesocket(Socket);
WSACleanup();
}
}
return 0;
}
Client code:
int main() {
WSADATA Winsock;
SOCKET Socket, Sub;
Addr addr;
IncomingAddress incomingAddress;
int AddressLen = sizeof(IncomingAddress);
WSAStartup(MAKEWORD(2, 2), &Winsock);
if (LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2) {
WSACleanup();
return 0;
}
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ZeroMemory(&addr, sizeof(Addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(6000);
if (connect(Socket, (sockaddr*) &addr, sizeof(Addr)) < 0) {
printf("Connection Failed!\n");
getchar();
return 0;
}
char *ClientIP = inet_ntoa(incomingAddress.sin_addr);
int ClientPort = ntohs(incomingAddress.sin_port);
printf("Client connected!\n");
printf("IP: %s:%d\n", ClientIP, ClientPort);
printf("Sending file... \n");
FILE *File;
char *Buffer;
unsigned long Size;
File = fopen("test.txt", "rb+");
if (!File) {
printf("Error while reading the file!\n");
getchar();
return 0;
}
fseek(File, 0, SEEK_END);
Size = ftell(File);
fseek(File, 0, SEEK_SET);
Buffer = malloc(Size);
fread(Buffer, Size, 1, File);
char cSize[MAX_PATH];
sprintf(cSize, "%i", Size);
fclose(File);
send(socket, cSize, MAX_PATH, 0); // File size
int Offset = 0;
while (Size > Offset) {
int Amount = send(Sub, Buffer + Offset, Size - Offset, 0);
if (Amount <= 0) {
printf("Error: " + WSAGetLastError());
break;
} else {
Offset += Amount;
}
}
free(Buffer);
closesocket(Sub);
closesocket(Socket);
WSACleanup();
printf("File sent!\n");
return 0;
}
You have three problems, one in the client and two in the server.
In the client you are sending the size of the file through Socket, which is correct. But then you use the unconnected and uninitialized socket Sub to send the data of the file.
In the server you have almost the opposite problem, where you attempt to receive both the size and the data through the passive listening socket instead of the accepted connection socket Sub.
Also in the server, if there's an error when reading the data you report it, but then you write data to the file anyway. In this case it will be some uninitialized data of unknown length.
Use correct sockets, and if there's an error don't do things you should not do.
And actually do some error checking. When receiving the size in the server, you don't check for errors, just that the connection wasn't closed by the other end of the connection.

Client-side not creating file

So, I have a working socket. I'm basically making a socket to allow me to transfer files from one program to another program. Everything is working except on the client side, it won't create the file?
Server:
int main() {
WSADATA Winsock;
SOCKET Socket, Sub;
Addr addr;
IncomingAddress incomingAddress;
int AddressLen = sizeof(IncomingAddress);
// Start up Winsock
WSAStartup(MAKEWORD(2, 2), &Winsock);
if (LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2) {
WSACleanup();
return 0;
}
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// Memset alternative
ZeroMemory(&addr, sizeof(Addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(portNumber);
bind(Socket, (sockaddr*) &addr, sizeof(Addr));
if (listen(Socket, 1) == SOCKET_ERROR) {
printf("Listening error!\n");
} else {
printf("Listening...\n");
}
if (Sub = accept(Socket, (sockaddr*) &incomingAddress, &AddressLen)) {
char *ClientIP = inet_ntoa(incomingAddress.sin_addr);
int ClientPort = ntohs(incomingAddress.sin_port);
printf("Client connected!\n");
printf("IP: %s:%d\n", ClientIP, ClientPort);
printf("Sending file... \n");
FILE *File;
char *Buffer;
unsigned long Size;
File = fopen("test.txt", "rb+");
if (!File) {
printf("Error while reading the file!\n");
getchar();
return 0;
}
fseek(File, 0, SEEK_END);
Size = ftell(File);
fseek(File, 0, SEEK_SET);
Buffer = malloc(Size);
fread(Buffer, Size, 1, File);
char cSize[MAX_PATH];
sprintf(cSize, "%i", Size);
fclose(File);
send(Sub, cSize, MAX_PATH, 0); // File size
}
return 0;
}
Client:
int main() {
WSADATA Winsock;
SOCKET Socket;
Addr addr;
IncomingAddress incomingAddress;
int AddressLen = sizeof(IncomingAddress);
WSAStartup(MAKEWORD(2, 2), &Winsock);
if (LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2) {
WSACleanup();
return 0;
}
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ZeroMemory(&addr, sizeof(Addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(6000);
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 = malloc(1024);
if (recv(Socket, Filesize, 1024, 0)) { // File Size
Size = atoi((const char*) Filesize);
printf("File size: %d\n", Size);
}
char *Buffer = malloc(Size);
int Offset = 0;
while (Size > Offset) {
int Amount = recv(Socket, Buffer + Offset, Size - Offset, 0);
if (Amount <= 0) {
printf("Error: " + WSAGetLastError());
break;
} else {
Offset += Amount;
printf("2\n");
}
}
FILE *File;
File = fopen("test.txt", "wb+");
fwrite(Buffer, 1, Size, File);
fclose(File);
getchar();
closesocket(Socket);
WSACleanup();
return 0;
}
You're sending merely the lenght of the file, but not the file itself to the client:
send(Sub, cSize, MAX_PATH, 0); // File size
This never recieves anything:
int Amount = recv(Socket, Buffer + Offset, Size - Offset, 0);
So yeah, just send the actual file as well.

UDP socket: server sending file to client Address family not supported by protocol family

I am just a beginner in socket programming and currently working on an small program dealing with file transfer using UDP. This program is written in C.
Here is my problem:
UDP server will first use the recvfrom() function to catch message from UDP client so to start sending a file. I sent the file name first, and it couldn't went through, appearing with: Address family not supported by protocol family as the error message(). I checked the sin_family of client_addr, and it is 7. Furthermore, after I tried to set client_addr.sin_family = AF_INET; the server worked fine, except that the client couldn't even receive any message.
I have checked some sources but it happened to be not so helpful, please if anyone knows why and willing to tell. Appreciate all your help.
Below is a short portion of server code:
int socketfd;
/* my address information */
struct sockaddr_in server_addr;
/* connector’s address information */
struct sockaddr_in client_addr;
socklen_t clientLength;
int numbytes;
char buffer[BUFLEN];
int portNum = atoi(port);
time_t timer;
char charfileSize[20];
int percent, count = 0;
struct tm *tm_info;
char timeBuf[30];
if((socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
perror("Server-socket() sockfd error lol!");
exit(1);
} else {
printf("Server-socket() sockfd is OK...\n");
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(portNum);
server_addr.sin_addr.s_addr = INADDR_ANY;
memset(&(server_addr.sin_zero), 0, 8);
// bind the socket to the server ip address
if(bind(socketfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
perror("server socket bind to IP error lol!\n");
exit(1);
} else {
printf("successfully bind server ip with socket ...\n");
}
// client_addr.sin_port = htons(portNum);
client_addr.sin_family = AF_INET;
//* for ensuring client connection *//
int tempGet;
char tempBuf[BUFLEN];
//if( (tempGet = recvfrom(socketfd, tempBuf, BUFLEN, 0, (struct sockaddr *)&client_addr, &clientLength)) > 0 ) {
tempGet = recvfrom(socketfd, tempBuf, BUFLEN, 0, (struct sockaddr *)&client_addr, &clientLength);
if( strcmp( tempBuf, "send file" ) == 0) {
printf("Can start transferring file...\n");
}
printf("sin family:%d\n", client_addr.sin_family);
FILE *fp = fopen(filename, "rb");
if ( !fp ) {
perror("Error opening the file\n");
exit(1);
} else {
// successfully opened the file that's going to be transferred
printf("file opened: %s\n", filename);
// get file size
int file_block_size = 0;
bzero(buffer, BUFLEN);
long file_size;
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
// goes back to the beginning of file(fp)
rewind(fp);
printf("file name: %s\n", filename);
printf("file size: %ld kb\n", file_size/1024);
// get time
time(&timer);
clientLength = sizeof(client_addr);
//client_addr.sin_family = AF_INET;
int sendFileName;
// length of file name
if( (sendFileName = sendto(socketfd, filename, strlen(filename), 0, (struct sockaddr *)&client_addr, sizeof(struct sockaddr_in))) >= 0) {
printf("file name sent.\n");
} else {
//printf("%d\n", sendFileName);
perror("file name send error.\n");
exit(1);
}
}
The last argument to recvfrom takes the address of a socklen_t which needs to be initialized with the size of the sockaddr parameter. I don't see clientLength initialized prior to this call, so client_addr is probably not being updated properly when this function returns. This causes the subsequent call to sendto to fail.
If you initialize clientLength before calling recvfrom that will take care of the problem.
clientLength = sizeof(client_addr);
tempGet = recvfrom(socketfd, tempBuf, BUFLEN, 0, (struct sockaddr *)&client_addr, &clientLength);
I am slightly tired of all incorrect and half-correct UDP socket program attempts at Stack Overflow. I have decided to do the reference UDP implementation, taking this question as an example. Next time I see TCP question (and have some time and energy) I will do reference TCP implementation.
This implementation does everything correctly (to the best of my knowledge :). It uses BSD sockets, so Windows implementations will have to make minor changes. Other than that, it should be C-99 conforiming in all.
Errors handling: application checks for possible errors, but does not try to correct them, simply reports. It also is known to leak a socket in certain error conditions (which lead to application shutdown), but adding proper socket close in this case will simply warrant for more code without actually adding a lot of benefit.
Compilation:
gcc -std=c99 -g -D_POSIX_SOURCE -Wall -Werror -pedantic -o test_udp send_udp.c
Usage: ./test_udp server or ./test_udp <hostname> <filename>
Behold: I give you test_udp.c.
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
const short port = 4321;
int run_server();
int send_file(const char* const server, const char* const file);
int main(int argc, char* argv[]) {
if (argc < 2 || argc > 3) {
printf("Error: Usage send_udp (server|<server_host>) [<file name>]\n");
return 1;
}
if (!strcmp(argv[1], "server"))
return run_server(); // runs forever
if (argc != 3) {
printf("Error: client mode accepts two arguments: server and file name.\n");
return 1;
}
return send_file(argv[1], argv[2]);
}
int run_server() {
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1) {
printf("run_server(): error creating socket: %s\n", strerror(errno));
return 2;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (struct sockaddr*)&addr, sizeof(addr))) {
printf("run_server(): error binding socket: %s\n", strerror(errno));
return 2;
}
printf("run_server(): socket created and bound, entering endless loop.\n");
struct sockaddr_in incoming;
socklen_t incoming_sz = sizeof(incoming);
char buff[USHRT_MAX]; // maximum size of UDP datagramm
const char* buff_ptr = buff;
while (1) {
ssize_t msg_size = recvfrom(sock, buff, sizeof(buff), 0, (struct sockaddr*)(&incoming), &incoming_sz);
if (msg_size == -1) {
printf("run_server(): error receiving message: %s\n", strerror(errno));
return 3;
}
if (msg_size == 0) {
printf("run_server(): a message of 0 size received from the client, bogus. Skipping, continue to listen.\n");
continue;
}
// Message structure: unsigned 16 bit length of file name (network order), followed by filename, followed by data
uint16_t fname_len;
if (msg_size < sizeof(fname_len)) {
printf("run_server(): Bogus (too short) message received from the client. Skipping, continue to listen.\n");
continue;
}
memcpy(&fname_len, buff_ptr, sizeof(fname_len));
fname_len = ntohs(fname_len);
buff_ptr += sizeof(fname_len);
msg_size -= sizeof(fname_len);
if (msg_size < fname_len) {
printf("run_server(): Bogus (too short) message received from the client. Skipping, continue to listen.\n");
continue;
}
char file_name[fname_len + 1];
strncpy(file_name, buff_ptr, fname_len);
file_name[fname_len] = '\0';
buff_ptr += fname_len;
msg_size -= fname_len;
printf("run_server(): incoming transfer for file %s, intrinsic file size: %zu\n", file_name, msg_size);
FILE* f = fopen(file_name, "wb");
if (!f) {
printf("run_server(): Could not open file for writing. Skipping the message, carrying on.\n");
continue;
}
size_t written = fwrite(buff_ptr, msg_size, 1, f);
if (written != 1)
printf("run_server(): error, could not write whole file.\n");
else
printf("run_server(): incoming file written successfully.\n");
fclose(f);
}
return 0;
}
int send_file(const char* const server, const char* const file) {
uint16_t fname_len = strlen(file);
uint16_t max_short = 0;
max_short = ~max_short;
if (fname_len > (max_short - sizeof(fname_len))) {
printf("send_file(): file name is toooo large. Can't send this file.\n");
return 2;
}
FILE* f = fopen(file, "rb");
if (!f) {
printf("send_file(): Could not open file for reading. Nothing sent.\n");
return 3;
}
fseek(f, 0, SEEK_END);
unsigned long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
if (fsize > max_short - sizeof(fname_len) - fname_len) {
printf("send_file(): file is toooo large. Can't send this file.\n");
fclose(f);
return 2;
}
char buff[sizeof(fname_len) + fname_len + fsize];
char* buff_ptr = buff;
uint16_t net_fname_len = htons(fname_len);
memcpy(buff_ptr, &net_fname_len, sizeof(net_fname_len));
buff_ptr += sizeof(net_fname_len);
memcpy(buff_ptr, file, fname_len);
buff_ptr += fname_len;
size_t rc = fread(buff_ptr, fsize, 1, f);
if (rc != 1) {
printf("send_file(): Could not read whole file. Error.\n");
fclose(f);
return 3;
}
fclose(f);
struct addrinfo* ainfo;
if (getaddrinfo(server, NULL, NULL, &ainfo) != 0) {
printf("send_file(): Unknown host %s.\n", server);
return 3;
}
struct addrinfo* ainfo_begin = ainfo;
// I will take the first IP v4 entry in possible addressess
while (ainfo->ai_family != AF_INET && ainfo->ai_next)
ainfo = ainfo->ai_next;
if (ainfo->ai_family != AF_INET) {
printf("send_file(): Couldn't resolve host %s to AF_INET address.\n", server);
return 3;
}
int addr = ((struct sockaddr_in*)(ainfo->ai_addr))->sin_addr.s_addr;
freeaddrinfo(ainfo_begin);
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1) {
printf("read_file(): error creating socket: %s\n", strerror(errno));
return 2;
}
struct sockaddr_in remote_addr;
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(port);
remote_addr.sin_addr.s_addr = addr;
ssize_t sent = sendto(sock, buff, sizeof(buff), 0, (struct sockaddr*)(&remote_addr), sizeof(remote_addr));
if (sent != sizeof(buff))
printf("read_file(): error sending message over socket: %s, only %zu bytes sent.\n", strerror(errno), sent);
else
printf("read_file(): file sent successfully.\n");
return sent == sizeof(buff) ? 0 : 3;
}

Sending a file over a TCP/IP socket (web server)

I'm writing the barebones of a web server, but I can't figure out why my file isn't be sent over my socket, I'm connecting to it and everything it just not send()ing my file... What am I missing?
//CODE (server.c)
#include<netinet/in.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
int main(void) {
int create_socket, new_socket;
socklen_t addrlen;
int bufsize = 1024;
char *buffer = malloc(bufsize);
struct sockaddr_in address;
if ((create_socket = socket(AF_INET, SOCK_STREAM, 0)) > 0){
printf("The socket was created\n");
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(80);
if (bind(create_socket, (struct sockaddr *) &address, sizeof(address)) == 0){
printf("Binding Socket\n");
}
long fsize;
FILE *fp = fopen("index.html", "r");
fseek(fp, 0, SEEK_END);
fsize = ftell(fp);
rewind(fp);
char *msg = malloc(fsize + 1);
fread(msg, sizeof(msg), 1, fp);
while (1) {
if (listen(create_socket, 10) < 0) {
perror("server: listen");
exit(1);
}
if ((new_socket = accept(create_socket, (struct sockaddr *) &address, &addrlen)) < 0) {
perror("server: accept");
exit(1);
}
if (new_socket > 0){
printf("The Client is connected...\n");
}
recv(new_socket, buffer, bufsize, 0);
printf("%s\n", buffer);
write(new_socket, "HTTP/1.1 200 OK\n", 16);
write(new_socket, "Content-length: 46\n", 19);
write(new_socket, "Content-Type: text/html\n\n", 25);
/* write(new_socket, "<html><body><H1>Hello world</H1></body></html>",46); */
if((send(new_socket, msg, fsize+1, 0)) > 0){
printf("success");
}
else{
printf("failed");
}
close(new_socket);
}
close(create_socket);
return 0;
}
//FILE (index.html) *same directory
<html>
<body>
<h1>Hello World</h1>
</body>
</html>
The code is completely broken, for a dozen different reasons. Try something more like this instead:
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
bool writeDataToClient(int sckt, const void *data, int datalen)
{
const char *pdata = (const char*) data;
while (datalen > 0){
int numSent = send(sckt, pdata, datalen, 0);
if (numSent <= 0){
if (numSent == 0){
printf("The client was not written to: disconnected\n");
} else {
perror("The client was not written to");
}
return false;
}
pdata += numSent;
datalen -= numSent;
}
return true;
}
bool writeStrToClient(int sckt, const char *str)
{
return writeDataToClient(sckt, str, strlen(str));
}
int main(void){
int create_socket, new_socket;
char *buffer;
int bufsize = 1024;
struct sockaddr_in address;
socklen_t addrlen;
buffer = (char*) malloc(bufsize);
if (!buffer){
printf("The receive buffer was not allocated\n");
exit(1);
}
create_socket = socket(AF_INET, SOCK_STREAM, 0);
if (create_socket == -1){
perror("The socket was not created");
exit(1);
}
printf("The socket was created\n");
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(80);
if (bind(create_socket, (struct sockaddr *) &address, sizeof(address)) == -1){
perror("The socket was not bound");
exit(1);
}
printf("The socket is bound\n");
long fsize;
FILE *fp = fopen("index.html", "rb");
if (!fp){
perror("The file was not opened");
exit(1);
}
printf("The file was opened\n");
if (fseek(fp, 0, SEEK_END) == -1){
perror("The file was not seeked");
exit(1);
}
fsize = ftell(fp);
if (fsize == -1) {
perror("The file size was not retrieved");
exit(1);
}
rewind(fp);
char *msg = (char*) malloc(fsize);
if (!msg){
perror("The file buffer was not allocated\n");
exit(1);
}
if (fread(msg, fsize, 1, fp) != 1){
perror("The file was not read\n");
exit(1);
}
fclose(fp);
printf("The file size is %ld\n", fsize);
if (listen(create_socket, 10) == -1){
perror("The socket was not opened for listening");
exit(1);
}
printf("The socket is listening\n");
while (1) {
addrlen = sizeof(address);
new_socket = accept(create_socket, (struct sockaddr *) &address, &addrlen);
if (new_socket == -1) {
perror("A client was not accepted");
exit(1);
}
printf("A client is connected from %s:%hu...\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));
// I will leave it as an exercise for you to implement
// a proper HTTP request parser here...
int numRead = recv(new_socket, buffer, bufsize, 0);
if (numRead < 1){
if (numRead == 0){
printf("The client was not read from: disconnected\n");
} else {
perror("The client was not read from");
}
close(new_socket);
continue;
}
printf("%.*s\n", numRead, buffer);
if (!writeStrToClient(new_socket, "HTTP/1.1 200 OK\r\n")){
close(new_socket);
continue;
}
char clen[40];
sprintf(clen, "Content-length: %ld\r\n", fsize);
if (!writeStrToClient(new_socket, clen)){
close(new_socket);
continue;
}
if (!writeStrToClient(new_socket, "Content-Type: text/html\r\n")){
close(new_socket);
continue;
}
if (!writeStrToClient(new_socket, "Connection: close\r\n\r\n") == -1){
close(new_socket);
continue;
}
//if (!writeStrToClient(new_socket, "<html><body><H1>Hello world</H1></body></html>")){
if (!writeDataToClient(new_socket, msg, fsize)){
close(new_socket);
continue;
}
printf("The file was sent successfully\n");
close(new_socket);
}
close(create_socket);
return 0;
}
fsize = ftell(fp);
rewind(fp);
char *filebuff = malloc(fsize + 1);
Why fsize+1? You don't need the +1.
fread(filebuff, sizeof(filebuff), 1, fp);
Unchecked return value. The second argument should be fsize. At present you're only passing the sizeof the pointer.
//create/bind socket
if ((create_socket = socket(AF_INET, SOCK_STREAM, 0)) > 0)
{
printf("The socket was created\n");
}
If the socket creation fails you must (a) print a proper error message as described below and (b) not just continue with execution as though the error hadn't occurred.
if (bind(create_socket, (struct sockaddr *) &address, sizeof(address)) == 0)
{
printf("Binding Socket\n");
}
Ditto.
//listen, create new_sock, write headers, send file
while (1){
if (listen(create_socket, 10) < 0) {
perror("server: listen");
exit(1);
}
The listen() call should be ahead of the loop, not inside it. This is the first time you've actually handled a failure case.
new_sock = accept(sock, (struct sockaddr *) &address, &addrlen);
recv(new_socket, buffer, bufsize, 0);
printf("%s\n", buffer);
Invalid. Unchecked return code. The buffer is only valid at all if recv() returned a positive integer, and only that many bytes of it are valid. It should be:
int count = recv(new_socket, buffer, bufsize, 0);
printf("%.*s\n", count, buffer);
Then we start on HTTP:
write(new_sock, "HTTP/1.1 200 OK\n", 16);
write(new_sock, "Content-length: 46\n", 19);
write(new_sock, "Content-Type: text/html\n\n", 25);
The line terminator in HTTP is inherited from Telnet and it is specified as \r\n, not \n.
if(send(new_sock, filebuff, fsize+1, 0) > 0){
printf("success");
}
else{
printf("failed");
}
Inadequate. If you get an error from any system call, you must call perror(), or use errno or strerror() in an error message. "Failed" conveys no useful information, and debugging becomes a mere guessing game. Don't write code like this. You should use perror() or whatever you decide for all the other unchecked return values above.
But there is a bigger problem. You're assuming that the file fits into memory. There is no need for that assumption. Just copy the file using an 8k buffer as follows:
int count;
while ((count = read(in, buffer, sizeof buffer)) > 0)
{
send(out, buffer, count, 0);
}
if (count < 0)
{
perror("send failed");
}
I would avoid stdio for this, it has too many issues, such as the poorly designed fread() and fwrite() function APIs.
Other then the wrong size used in various places (as noted by mathematician1975), your "real" problem is that your trying to communicate with a browser that expects an HTTP server.
HyperText Transfer Protocol is, well, a protocol. It is more complex then a simple connection and a dump of content.
You have to parse the request according to it, and send headers and content in a certain way.
Check to see if bind() is failing and report if so. You're binding to port 80; under Unix-like operating systems only root can bind to reserved ports (less than 1024).
Update 1:
You must initialize addrlen to sizeof(address) before calling accept(). From http://linux.die.net/man/2/accept:
The addrlen argument is a value-result argument: the caller must
initialize it to contain the size (in bytes) of the structure pointed
to by addr; on return it will contain the actual size of the peer
address.

File size changes after sending it through socket

When sending a file through socket from client to server the file size changes. Where the problem may be?
Here is the client's side code:
char chunk[512];
host_info = gethostbyname(server);
if (host_info == NULL) {
perror("get host by name");
exit(errno);
}
socket_desc = socket(AF_INET, SOCK_STREAM, 0);
if (socket_desc < 0) {
perror("socket");
exit(errno);
}
server_address.sin_family = host_info->h_addrtype;
memcpy((char *) &server_address.sin_addr.s_addr, host_info->h_addr_list[0], host_info->h_length);
server_address.sin_port = htons(PORT);
if (connect(socket_desc, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) {
perror("connect");
exit(errno);
}
file_to_send = fopen (lfile,"rb");
if(!file_to_send) {
perror("fopen");
close(socket_desc);
exit(errno);
} else {
long file_size;
fseek (file_to_send, 0, SEEK_END);
file_size = ftell (file_to_send);
rewind(file_to_send);
while(totally_read < file_size){
chunk[0] = '\0';
bytes_read = fread(chunk, sizeof(char), sizeof(chunk), file_to_send);
totally_read += bytes_read;
int sent = send(socket_desc, chunk, bytes_read, 0);
if(sent < 0){
perror("connect");
exit(errno);
}
totally_sent += sent;
printf("read: %7db sent: %7db totally read: %7db totally sent: %7db\n", bytes_read, sent, totally_read, totally_sent);
}
And here is the server side:
char chunk[512];
listen_socket = socket(AF_INET, SOCK_STREAM, 0);
if (listen_socket < 0) {
perror("socket");
close(listen_socket);
exit(errno);
}
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(PORT);
if (bind(listen_socket, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) {
perror("bind");
close(listen_socket);
exit(errno);
}
listen(listen_socket, 5);
client_address_length = sizeof(client_address);
while(1){
connect_socket = accept(listen_socket, (struct sockaddr *) &client_address, &client_address_length);
if (connect_socket < 0) {
perror("accept");
close(listen_socket);
exit(errno);
}
recv_file = fopen(filename,"wb");
int received = 0;
int totally_wrote = 0, totally_received = 0;
while(1){
chunk[0] = '\0';
received = recv(connect_socket, chunk, sizeof(chunk), 0);
if(received < 0) {
perror("recv");
} else if(received > 0) {
int wrote = fwrite(chunk, sizeof(char), received, recv_file);
totally_wrote +=wrote;
totally_received += received;
printf("received: %7db wrote: %7db totally received: %7db torally wrote: %7db\n", received, wrote, totally_received, totally_wrote);
} else {
printf("Complete!\n");
break;
}
}
When sending a text file I get the following output
on the client side:
totally read: 299695b | totally sent: 299695b
but on the server side:
totally received: 303279b | torally wrote: 303279b
I've opened the file with the editor. The transmitted file is practically the same with the source file, except for some strange data in the beginning. The transmitted file 3584 bytes of additionsl binary data in the beginning if the chunk size is 512 bytes. It adds 3840 bytes if i change the chunk size to 256 bytes.
You are not checking the return value from send()
Send() can return any value between -1 and the third (length) argument, inclusive. You assume any return value > 0 to be equal to the 3rd argument. They need not be.
to deal with short send()s (or recv()s (or read() / write()) you'll need something like:
int sent, pos, bytes_read;
bytes_read = fread(chunk, sizeof(char), sizeof(chunk), file_to_send);
totally_read += bytes_read;
for (pos = 0; pos < bytes_read; pos += sent) {
sent = send(socket_desc, chunk+pos, bytes_read-pos, 0)
switch(sent) {
case -1: /* handle errno here, especially EAGAIN/EINTR */
case 0: /*handle EOF here */
break;
default:
break;
}
}
totally_sent += pos;

Resources