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

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.

Related

C: TCP server could not receive message from client

I am a C beginner. I want to send a file by TCP. The client reads content from a txt file and sent it to server. Read method is ok. It reads the specified bytes from the file. Send method dose not throw any exception. However the server receives nothing. I try to solve it for a whole day. I fail.
Please help me check what is wrong with my code.
As comment advice, I edit my code again. Now there are two problem. One is that in the client loop the return values from client fread() and send() is greater than 0 for the first two times while the server accept() is still blcoked without getting message from client.
The second problem. In the third client loop, the return value of client fread() is still greater than 0, but the return value of send() is -1.I try to open the file in binary mode rb instead of r. It is the same problem.
the edited client code:
#include <stdio.h>
#include <winsock.h>
#include <time.h>
#pragma comment(lib, "WS2_32.lib")
#define MAXLINE 1024*4
SOCKET sockClient;// = socket(AF_INET,SOCK_DGRAM,0);
SOCKADDR_IN servAddr;
int main(void) {
WSADATA wsd;
FILE *fp;
int read_len;
char buf2[MAXLINE];
time_t t_start, t_end;
if ((fp = fopen("file.txt", "r")) == NULL) {
perror("Open file failed\n");
exit(0);
}
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) {
printf("WSAStartup failed !\n");
return 1;
}
sockClient = socket(AF_INET, SOCK_STREAM, 0);
servAddr.sin_family = AF_INET;
servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
servAddr.sin_port = htons(5000);
/* connect the server commanted by guoqingbo*/
int i_ret = connect(sockClient, (struct sockaddr *) &servAddr, sizeof(struct sockaddr));
if (-1 == i_ret) {
perror("Connect socket failed!\n");
exit(0);
}
printf("client starts\n");
t_start = time(NULL);
while (1) {
read_len = fread(buf2, sizeof(char), MAXLINE, fp);
if (read_len < 0) {
perror("read data failed\n");
break;
} else if (read_len == 0) {
printf("read finished\n");
}
int send_len = send(sockClient, buf2, read_len, 0);
if (send_len < 0) {
perror("Send data failed\n");
exit(0);
} else if (send_len == 0) {
printf("send finished\n");
break;
}
}
t_end = time(NULL);
printf("The time used %f s\n", difftime(t_end, t_start));
fclose(fp);
closesocket(sockClient);
WSACleanup();
return 0;
}
the edited server code:
#include <stdio.h>
#include <WINSOCK2.H>
#include <strings.h>
#include <stdlib.h>
#pragma comment(lib, "WS2_32.lib")
#define BUF_SIZE 1024*4
SOCKET socketSrv;
SOCKADDR_IN addrSrv;
SOCKADDR_IN addrClient;
char buf[BUF_SIZE];
int main(void) {
WSADATA wsd;
int nRet;
int recv_len;
FILE *fp;
if ((fp = fopen("file.txt", "w")) == NULL) {
perror("Creat file failed");
exit(0);
}
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) {
printf("WSAStartup failed !\n");
return 1;
}
socketSrv = socket(AF_INET, SOCK_STREAM, 0);
int len = sizeof(SOCKADDR);
ZeroMemory(buf, BUF_SIZE);
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(5000);
nRet = bind(socketSrv, (SOCKADDR *) &addrSrv, sizeof(SOCKADDR));
if (SOCKET_ERROR == nRet) {
printf("bind failed !\n");
closesocket(socketSrv);
WSACleanup();
return -1;
}
if (SOCKET_ERROR == listen(socketSrv, 10)) {
printf("Server Listen Failed: %d", WSAGetLastError());
exit(1);
}
printf("server started..\n");
while (1) {
SOCKET m_New_Socket = accept(socketSrv, (SOCKADDR *) &addrClient, &len);
if (SOCKET_ERROR == m_New_Socket) {
printf("Server Accept Failed: %d", WSAGetLastError());
break;
}
if (recv_len = recv(socketSrv, buf, BUF_SIZE, 0) < 0) {
printf("Server Receive Data Failed!");
break;
}
int write_length = fwrite(buf, sizeof(char), recv_len, fp);
if (write_length < recv_len) {
printf("File write failed\n");
break;
}
}
fclose(fp);
closesocket(socketSrv);
WSACleanup();
return 0;
}

file server in C doesn't continually return files when requested

I'm new to network programming and recently finished reading through Beej's guide. I have a client/server program that I'm trying to get to continuously have the server return the contents of a file when the client requests it.
It works by the client sending the server a file path and the server reading it (if it exists) into a buffer then sending the buffer to the client which just prints the buffer.
It works, but it will only return one file then ignores any following requests. I have to shut down the client and reconnect again for it to work again. I can't figure out why. I've tried implementing select() and used aio_read() over the standard read() and I also forking a process for the send() function. Each of those those experiments had it working exactly the same pretty much.
Anyone have any tips? I'm at a loss where the problem could be.
Client
#define MAXDATASIZE 100 // max number of bytes at once
#define MAXMSG 25
#define MAXDATA 4096
#define SA struct sockaddr
// clean_str: make sure the string doesn't have junk spaces around it
void clean_str(char *s)
{
size_t len = strlen(s);
char tmp[MAXMSG] = {0};
strncpy(tmp, s, len-1);
memset(s, 0, len);
strncpy(s, tmp, len-1);
}
int main(int argc, char **argv)
{
int sockfd, numbytes;
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
char file_request[MAXMSG] = {0};
char file_buf[MAXDATA];
if (argc != 3) {
fprintf(stderr, "usage: client <hostname> <port>\n");
exit(EXIT_FAILURE);
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
// load the struct
if ((rv = getaddrinfo(argv[1], argv[2], &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
exit(EXIT_FAILURE);
}
// loop trhough all results and connect to the first one we can
for (p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) {
perror("client: socket");
continue;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) < 0) {
close(sockfd);
perror("client: connect");
continue;
}
// if we make it here, we've got a connection
break;
}
if (p == NULL) {
fprintf(stderr, "client: failed to connect\n");
exit(EXIT_FAILURE);
}
inet_ntop(p->ai_family, (SA*)&p->ai_addr, s, sizeof s);
printf("client: connecting to %s\n", s);
freeaddrinfo(servinfo);
// stay connect until client exits
int n;
while (1) {
// make sure everything is cleared to minimize issues
memset(file_buf, 0, MAXDATA);
memset(file_request, 0, sizeof MAXMSG);
numbytes = 0;
// get client request from stdin
int b = read(STDIN_FILENO, file_request, MAXMSG);
if (b < 0) {
perror("client: read");
}
clean_str(file_request);
// send the request to the server
if ((numbytes = send(sockfd, file_request, strlen(file_request), 0)) < 0) {
perror("send");
exit(EXIT_FAILURE);
}
// now we wait for a response
while ((n = read(sockfd, file_buf, MAXDATA-1)) > 0)
printf("%s\n", file_buf);
if (n < 0) {
perror("read");
}
}
return 0;
}
Server
#define PORT 3490
#define MAXDATA 4096
#define FILENAME 256
#define SA struct sockaddr // for less messy casting
// get_file: open file, read contents info a buffer, return buffer
char *get_file(const char *path) {
int n, bytes;
static char buf[MAXDATA];
// try to open file
n = open(path, O_RDONLY);
if (n < 0) {
strcpy(buf, "problem opening file");
printf("%s\n", buf);
return buf;
}
// if exists, read it into buffer on
bytes = read(n, buf, sizeof buf-1);
if (bytes < 0) {
strcpy(buf, "problem reading file");
printf("%s\n", buf);
return buf;
}
close(n);
return buf;
}
int main()
{
int sockfd, filefd;
struct sockaddr_in servaddr;
struct sockaddr_storage client_addr;
socklen_t len;
int nbytes;
char file_request[FILENAME]; // buf to hold client's request string
// clear servaddr struct
memset(&servaddr, 0, sizeof servaddr);
servaddr.sin_family = AF_INET; // IPv4 for simplicity
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // use my IP
servaddr.sin_port = htons(PORT); // short, network by order
// create socket file descriptor
// #param3 is the protocol. 0 means TCP
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
// bind the socket to the PORT
if (bind(sockfd, (SA*)&servaddr, sizeof servaddr) < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
// this prevents the 'bind: address already in use' issue
int yes = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) < 0) {
perror("setsocket");
exit(EXIT_FAILURE);
}
if (listen(sockfd, 10) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
printf("server running and waiting for connection...\n");
int open = 1; // keep track if there's an accepted() fd
char *open_file;
while (1) {
// clear the file_request buffer
memset(file_request, 0, FILENAME);
memset(&open_file, 0, sizeof open_file);
nbytes = 0;
if (open) {
// we're only going to connect to one client for now
len = sizeof client_addr;
filefd = accept(sockfd, (SA*)&client_addr, &len);
if (filefd < 0) {
perror("accept");
continue;
} else {
printf("connected to a client\n");
open = 0; // keep track that there's an open fd
}
}
// recieve data from a client
if ((nbytes = recv(filefd, file_request, sizeof file_request, 0)) <= 0) {
// got error or connection was closed by client
if (nbytes == 0) {
printf("file-server: client hung up\n");
close(filefd);
open = 1;
continue;
} else {
perror("recv");
close(filefd);
open = 1;
continue;
}
close(filefd);
} else {
// we got some data
// manage it and get file contents
open_file = get_file(file_request);
if (strcmp(open_file, "0") == 0) {
continue;
}
if (send(filefd, open_file, strlen(open_file), 0) < 0) {
perror("send");
continue;
}
}
}
close(sockfd);
return 0;
}

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.

C TCP sockets, echo server with file sending, hangs up after sending a file

I wanted to write a simple TCP echo server application. I managed to do the echo part, but have some problems with sending files between client and server. The idea is simple: despite sending ordinary messages, client can send a special command to server (\SENDFILE filename.txt), and after receiving such command, server should ask client for this file, and get the file from client. (Further I would like to get a file from one client, and later send it to another one).
I think "the protocol" here is simple, however, after typing \SENDFILE at client's side, client hangs up, and does not receive any further messages from server. Moreover (server and client are in different directories) at server's side there's only an empty file from client, with no content inside.
Any ideas what can be wrong here?
client.c
#include<stdio.h> //printf
#include<string.h> //
#include <sys/stat.h>
#include<sys/socket.h> //socket
#include<arpa/inet.h> //inet_addr
#include <fcntl.h>
#define SERVER_PORT 9034
#define BUFF_SIZE 2000
int sendall(int s, char *buf, int len)
{
int total = 0;
int bytesleft = len;
int n;
while(total < len)
{
n = send(s, buf+total, bytesleft, 0);
if (n == -1)
break;
total += n;
bytesleft -= n;
}
return n==-1?-1:0;
}
void SendMsgToSender(char *msg, int connfd)
{
write(connfd, msg, strlen(msg));
memset(msg, 0, BUFF_SIZE);
}
int main(int argc , char *argv[])
{
int sock;
struct sockaddr_in server;
char bufferOUT[BUFF_SIZE] , bufferIN[BUFF_SIZE];
struct stat file_stat;
memset(bufferOUT, 0, BUFF_SIZE);
memset(bufferIN, 0, BUFF_SIZE);
//Create socket
sock = socket(AF_INET , SOCK_STREAM , 0);
if (sock == -1)
{
printf("Could not create socket");
}
// puts("Socket created");
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( SERVER_PORT );
//Connect to remote server
if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0)
{
perror("Connect failed. Error");
return 1;
}
// puts("Connected\n");
int read_size = 10;
//keep communicating with server
while(1)
{
printf("> ");
fgets(bufferOUT, BUFF_SIZE, stdin);
//Send some data
if( send(sock , bufferOUT , BUFF_SIZE , 0) < 0)
{
perror("Send failed");
return 1;
}
//Receive a reply from the server
if( (read_size = recv(sock , bufferIN , BUFF_SIZE , 0)) < 0)
{
perror("Recv failed");
break;
}
if(read_size == 0)
break;
if(bufferIN[0] == '\\')
{
char tmp[BUFF_SIZE], filename[BUFF_SIZE], *param;
memset(filename, BUFF_SIZE, 0);
strcpy(tmp, bufferIN);
param = strtok(tmp, " ");
if(param != NULL)
{
if(!strcmp(param, "\\GIVEMEFILE"))
{
param = strtok(NULL, " ");
if(param != NULL)
{
strcpy(filename, param);
FILE * fp;
int nBytes;
char buffer[BUFF_SIZE], *s;
memset(buffer, 0, BUFF_SIZE);
fp = fopen(filename, "r");
if(fp == NULL)
{
perror("fopen");
fflush(stdout);
break;
}
int remain_data = file_stat.st_size;
do
{
s = fgets(buffer, BUFF_SIZE, fp);
if(s != NULL && buffer[0] != EOF)
{
nBytes = sendall(sock, buffer, BUFF_SIZE);
remain_data -= nBytes;
}
else
break;
}
while((s != NULL) && (nBytes > 0) && (remain_data > 0));
fclose(fp);
memset(bufferOUT, 0, BUFF_SIZE);
memset(bufferIN, 0, BUFF_SIZE);
continue;
}
}
}
}
else
{
printf("%s\n", bufferIN);
fflush(stdout);
}
memset(bufferOUT, 0, BUFF_SIZE);
memset(bufferIN, 0, BUFF_SIZE);
}
close(sock);
return 0;
}
server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#include <fcntl.h>
#define SERVER_PORT 9034
#define BUFF_SIZE 2000
void StripNewline(char *s)
{
while(*s != '\0')
{
if(*s == '\r' || *s == '\n')
{
*s = '\0';
}
s++;
}
}
void SendMsgToSender(char *msg, int connfd)
{
write(connfd, msg, strlen(msg));
memset(msg, 0, BUFF_SIZE);
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET)
{
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int GetFileFromClient(int connfd, char *filename)
{
FILE * fp = NULL;
int bytes;
char buffer[BUFF_SIZE];
memset(buffer, 0, BUFF_SIZE);
fp = fopen(filename, "w");
if(fp == NULL)
return 0;
memset(buffer, 0, BUFF_SIZE);
sprintf(buffer, "\\GIVEMEFILE %s \r\n", filename);
SendMsgToSender(buffer, connfd);
while(1)
{
memset(buffer ,0 , BUFF_SIZE);
if((bytes = recv(connfd , buffer , BUFF_SIZE , 0) ) <= 0)
return 0;
else
fprintf(fp, "%s\n", buffer);
}
fclose(fp);
sleep(1);
memset(buffer, 0, BUFF_SIZE);
sprintf(buffer, "\r\n");
SendMsgToSender(buffer, connfd);
return 1;
}
int main(void)
{
fd_set master;
fd_set read_fds;
int fdmax;
int listener;
int client_sock;
struct sockaddr_storage remoteaddr;
socklen_t addrlen;
char bufferIN[BUFF_SIZE], bufferOUT[BUFF_SIZE], tmp[BUFF_SIZE], *datetime;
int nbytes;
char remoteIP[INET6_ADDRSTRLEN];
int yes=1;
int i, j, rv;
struct addrinfo hints, *ai, *p;
FD_ZERO(&master);
FD_ZERO(&read_fds);
memset(bufferIN, 0, BUFF_SIZE);
memset(bufferOUT, 0, BUFF_SIZE);
memset(tmp, 0, BUFF_SIZE);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
char port[16] = "9034";
if (getaddrinfo(NULL, port, &hints, &ai) < 0)
{
fprintf(stderr, "selectserver: %s\n", gai_strerror(rv));
exit(1);
}
for(p = ai; p != NULL; p = p->ai_next)
{
listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (listener < 0)
{
continue;
}
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
if (bind(listener, p->ai_addr, p->ai_addrlen) < 0)
continue;
break;
}
if (p == NULL)
exit(2);
freeaddrinfo(ai);
if (listen(listener, 10) == -1)
{
perror("listen");
exit(3);
}
FD_SET(listener, &master);
fdmax = listener;
printf("Server is running ...\n\n");
for(;;)
{
read_fds = master;
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1)
{
perror("select");
exit(4);
}
for(i = 0; i <= fdmax; i++)
{
if (FD_ISSET(i, &read_fds))
{
if (i == listener)
{
addrlen = sizeof remoteaddr;
client_sock = accept(listener,
(struct sockaddr *)&remoteaddr,
&addrlen);
if (client_sock == -1)
{
perror("accept");
}
else
{
FD_SET(client_sock, &master);
if (client_sock > fdmax)
fdmax = client_sock;
}
}
else
{
if ((nbytes = recv(i, bufferIN, BUFF_SIZE, 0)) <= 0)
{
if (nbytes == 0)
close(i);
else if(nbytes == -1)
{
perror("recv");
fflush(stdout);
}
close(i);
FD_CLR(i, &master);
}
else
{
bufferIN[nbytes-1] = '\0';
StripNewline(bufferIN);
strcpy(tmp, bufferIN);
if(bufferIN[0] == '\\')
{
char *command, *param;
command = strtok(bufferIN, " ");
if(!strcmp(command, "\\QUIT"))
{
close(i);
FD_CLR(i, &master);
break;
}
else if(!strcmp(command, "\\SENDFILE"))
{
param = strtok(tmp, " ");
if(param != NULL)
{
param = strtok(NULL, " ");
if(param != NULL)
{
printf("Client is sending me a file '%s'...\n", param);
GetFileFromClient(i, param);
}
}
}
else
{
SendMsgToSender(bufferIN, i);
}
memset(bufferIN, 0, BUFF_SIZE);
memset(bufferOUT, 0, BUFF_SIZE);
}
else
{
SendMsgToSender(bufferIN, i);
}
}
} // END handle data from client
} // END got new incoming connection
} // END looping through file descriptors
} // END for(;;)
memset(bufferIN, 0, BUFF_SIZE);
memset(bufferOUT, 0, BUFF_SIZE);
return 0;
}
strcpy(tmp, bufferIN);
Here you are assuming that whatever was read was null-terminated.
param = strtok(tmp, " ");
if(param != NULL)
{
if(!strcmp(param, "\\GIVEMEFILE"))
Here you are assuming that an entire message has been received.
strcpy(filename, param);
Ditto.
memset(buffer, 0, BUFF_SIZE);
Pointless. Remove.
do
{
s = fgets(buffer, BUFF_SIZE, fp);
Here you are assuming that the file consists of lines.
if(s != NULL && buffer[0] != EOF)
Testing buffer[0] !=EOF is meaningless. If you had reached EOF, s would have been null, assuming the file consists of lines, but there is nothing about a line that says anything about what its first character can be, other than that it isn't a line terminator.
memset(bufferOUT, 0, BUFF_SIZE);
memset(bufferIN, 0, BUFF_SIZE);
Both pointless. Remove.
memset(bufferOUT, 0, BUFF_SIZE);
memset(bufferIN, 0, BUFF_SIZE);
Ditto.
void StripNewline(char *s)
This method appears completely pointless. Remove.
void SendMsgToSender(char *msg, int connfd)
{
write(connfd, msg, strlen(msg));
Here you are sending a string to the peer without the trailing null, which the peer is looking for at strlen() above. Have a good think about what your application protocol actually entails.
memset(msg, 0, BUFF_SIZE);
Pointless. Remove.
int GetFileFromClient(int connfd, char *filename)
{
FILE * fp = NULL;
int bytes;
char buffer[BUFF_SIZE];
memset(buffer, 0, BUFF_SIZE);
Pointless. Remove.
memset(buffer, 0, BUFF_SIZE);
Ditto.
sprintf(buffer, "\\GIVEMEFILE %s \r\n", filename);
SendMsgToSender(buffer, connfd);
while(1)
{
memset(buffer ,0 , BUFF_SIZE);
Pointless. Remove.
if((bytes = recv(connfd , buffer , BUFF_SIZE , 0) ) <= 0)
return 0;
Here you need to distinguish between (1) bytes == 0, which means the peer disconnected, and (2) byte == -1, which indicates an error, which you need to log, via errno, strerror(), and friends.
else
fprintf(fp, "%s\n", buffer);
Change to fprintf(fp, "%.*s\n", bytes, buffer). You are assuming throughout that all messages are null-terminated by TCP. They aren't.
sleep(1);
Pointless. Remove.
memset(buffer, 0, BUFF_SIZE);
Ditto.
sprintf(buffer, "\r\n");
SendMsgToSender(buffer, connfd);
Sending a line terminator to the peer appears completely pointless.
memset(bufferIN, 0, BUFF_SIZE);
memset(bufferOUT, 0, BUFF_SIZE);
memset(tmp, 0, BUFF_SIZE);
All pointless. Remove.
if (bind(listener, p->ai_addr, p->ai_addrlen) < 0)
continue;
Here you need to print an error mesage instead of just ignoring the condition.
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1)
You haven't put the listening socket into non-blocking mode. Using select() is therefore pointless.
bufferIN[nbytes-1] = '\0';
StripNewline(bufferIN);
Why?
strcpy(tmp, bufferIN);
Why? What's wrong with continuing to use bufferIN?
if(bufferIN[0] == '\\')
{
char *command, *param;
command = strtok(bufferIN, " ");
Here again you are assuming a complete command was received, complete with trailing null.
memset(bufferIN, 0, BUFF_SIZE);
memset(bufferOUT, 0, BUFF_SIZE);
Both pointless. Remove. This is jut cargo-cult programming. recv() returns a length. Use it.
memset(bufferIN, 0, BUFF_SIZE);
memset(bufferOUT, 0, BUFF_SIZE);
Ditto, in spades.
Basically you have an application protocol problem. Specifically, you don't have an application protocol. Just a whole lot of unwarranted assumptions. If you want a trailing null, (a) send a trailing null, and (b) loop reading until you receive it. You also have an assumption about the content of the files being sent, which is completely unnecessary. Just read bytes from the file and send them to the server. No assumption about lines or line terminators necessary. If you're sending multiple files over the same connection you will need to send the file size ahead of the file, so the receiver will know exactly how many bytes to read and copy to the file.
In essence, you need to rethink this completely.
In client.c you have to initialize file_statbefore getting the size of the file stat(filename, &file_stat);
Because of this error remain_data will always have a wrong value.
In Server.c
Because of the error in the while loop as pointed out by EJP you are overwriting the file sent by the client. Basically making it empty.
Open the client filename with "r" option.
Open another file in the server and receive data to that file.
Small example to receive data of files within BUFF_SIZE. You can use the some logic and expand it to bigger files like its done in Client.c
fd = fopen(<new_file_path>, "w");
while(1)
{
memset(buffer ,0 , BUFF_SIZE);
if((bytes = recv(connfd , buffer , BUFF_SIZE , 0) ) == BUFF_SIZE)
break;
}
fprintf(fd, "%s\n", buffer);
fclose(fd);

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;
}

Resources