thanks for reading this. I've been stuck for about 5 hours on this bug and I can only imagine its the tiniest thing keeping me from moving on with this. I'm trying to write from scratch an FTP server/client. The client sends "get/send (filename)" and the server sends or receives it based on the clients command. I'm stuck in a pretty early stage, right now I am just trying to get it to open the file, read it or as much of it as it can to a buffer, and print it. Once I know it prints correctly, I'll send that buffer to my client. I'm stuck there though, it opens correctly as far as I know, in that it doesn't produce a null pointer. However it always segfaults after printing the file size and successfully sending that to the client (I've tried both open and read on a file descriptor as well as fopen and fread on a FILE *, I'm segfaulting on both which is why I think its a small error somewhere else.) All help is appreciated, here's my server code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#include <fcntl.h>
int main()
{
char str[100];
int listen_fd, comm_fd, rc;
struct sockaddr_in servaddr;
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
bzero( &servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htons(INADDR_ANY);
servaddr.sin_port = htons(60072);
bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
listen(listen_fd, 10);
comm_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL);
while(1) {
int bytes_read = 0, bytes_sent = 0;
int which = 0, i = 0, filesize = 0, fd;
size_t length;
int offset;
char *in[15], *token, filename[50];
struct stat stat_buf;
bzero( str, 100);
// Read client command
read(comm_fd,str,100);
printf("Seerver is processing command - %s", str);
// Parse client command and determine send/recv
token = strtok(str, " ");
while (token != NULL) {
in[i] = malloc(strlen(token) + 1);
strncpy(in[i], token, strlen(token));
i++;
if(strcmp(token, "get") == 0) which = 1;
if(strcmp(token, "send") == 0) which = 2;
if(strcmp(token, "exit") == 0) exit(0);
token = strtok(NULL, " ");
if(i == 1) {
strcpy(filename, token);
}
}
// Strip newline char sent with fgets
size_t ln = strlen(filename) - 1;
if (filename[ln] == '\n') {
filename[ln] = '\0';
}
// Code for SENDING file
if (which == 1) {
char buffer[100];
// Open file and send file size to client
stat(filename, &stat_buf);
filesize = stat_buf.st_size;
printf("%s successfully opened and has size of %d\n", filename, filesize);
send(comm_fd, &filesize, sizeof(filesize), 0);
FILE *fpt;
bzero(buffer, 100);
fopen(filename, "r");
fread(buffer, sizeof(char), 99, fpt);
printf("%s", buffer);
}
}
}
And here is my client code:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
int main(int argc,char **argv)
{
int sockfd, n;
char sendline[100];
char recvline[100];
char filedesc[100];
struct sockaddr_in servaddr;
sockfd=socket(AF_INET,SOCK_STREAM,0);
bzero(&servaddr,sizeof servaddr);
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(60072);
inet_pton(AF_INET,"127.0.0.1",&(servaddr.sin_addr));
connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
while(1)
{
int filesize = 0, fd, read_bytes = 0;
char buffer[1024];
bzero(sendline, 100);
bzero(recvline, 100);
bzero(filedesc, 100);
printf("Send: ");
fgets(sendline,100,stdin);
// Send filename and command to server
write(sockfd,sendline,strlen(sendline)+1);
// Receive file size from server
recv(sockfd, &filesize, sizeof(filesize), 0);
printf("The file is %d bytes\n", filesize);
fd = open("copy.txt", O_CREAT | O_WRONLY, 0644);
if (fd < 0) {
printf("Error creating copy of file");
exit(0);
}
//recv(sockfd, &buffer, filesize, 0);
//printf("%s", buffer);
}
}
I don't post here much at all, so if I can provide any other info for you guys or do something different in the future, I'm all for it.
Thanks again.
Related
I have been trying to get this FTP client/ server to work together but its currently not playing friendly
Bits of code that I have tested and that I couldn't find to work have been commented but also some of these commented recv and write lines work but to make the over all problem simpler i have commented them out for the time being. The problem seems to be in the ConnectionHandler function under the else if(strstr(client_request, "Put")) line of code. i have currently got successful FTP from the server to the client but the client to server part I'm struggling to get to work any advice would be grateful.
I feel as though this line is the problem file_desc = open(file_name, O_CREAT | O_EXCL | O_WRONLY, 0777); but i need to create the file to run to but file_desc returns -1 even though the file is created and I'm simply unable to determine why this is the case. Ultimately i may be overlooking something else.
Server
/*
* Compile & link : gcc server.c -lpthread -o server
* Execute : ./server
*/
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <pthread.h>
#define SERVER_PORT 8080
void* ConnectionHandler(void* socket_desc);
char* GetFilenameFromRequest(char* request);
bool SendFileOverSocket(int socket_desc, char* file_name);
int readn(int fd, char *buf, int bufsize)
{
short data_size; // sizeof (short) must be 2
int n, nr, len;
// check buffer size len
if (bufsize < BUFSIZ)
return (-3); // buffer too small
// get the size of data sent to me
if (read(fd, (char *) &data_size, 1) != 1)
return (-1);
if (read(fd, (char *) (&data_size)+1, 1) != 1)
return (-1);
len = (int) ntohs(data_size); // convert to host byte order
// read len number of bytes to buf
for (n=0; n < len; n += nr)
{
if ((nr = read(fd, buf+n, len-n)) <= 0)
return (nr); // error in reading
}
return (len);
}
int main(int argc, char **argv)
{
int socket_desc,
socket_client,
*new_sock,
c = sizeof(struct sockaddr_in);
struct sockaddr_in server,
client;
// Create socket
socket_desc = socket(AF_INET, SOCK_STREAM, 0);
if (socket_desc == -1)
{
perror("Could not create socket");
return 1;
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(SERVER_PORT);
if (bind(socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0)
{
perror("Bind failed");
return 1;
}
listen(socket_desc , 3);
while (socket_client = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c))
{
pthread_t sniffer_thread;
new_sock = malloc(1);
*new_sock = socket_client;
pthread_create(&sniffer_thread, NULL, ConnectionHandler, (void*) new_sock);
pthread_join(sniffer_thread, NULL);
}
if (socket_client<0)
{
perror("Accept failed");
return 1;
}
return 0;
}
void *ConnectionHandler(void *socket_desc)
{
int socket = *(int*)socket_desc;
char server_response[BUFSIZ],
client_request[BUFSIZ],
file_name[BUFSIZ];
recv(socket, client_request, BUFSIZ, 0); //Wait at this point to recieve a message from the client
if(strstr(client_request, "Get"))
{
perror("1");
strcpy(file_name, GetFilenameFromRequest(client_request));
// If requested file exists, notify the client and send it
if (access(file_name, F_OK) != -1){
perror("2");
strcpy(server_response, "OK");
write(socket, server_response, strlen(server_response));
perror("3");
SendFileOverSocket(socket, file_name);
perror("4");
}
else {
// Requested file does not exist, notify the client
strcpy(server_response, "NO");
write(socket, server_response, strlen(server_response));
}
}
else if(strstr(client_request, "Put"))
{
char *data, reply_msg[BUFSIZ];
char buff[BUFSIZ];
int file_size, file_desc;
perror("0.5");
strcpy(file_name, GetFilenameFromRequest(client_request));
perror("0.75");
//recv(socket, reply_msg, 2, 0); //Receive reply message from client if file exists
//fprintf(stderr, "File was found = %s", reply_msg);
//Create File
perror("1");
recv(socket, &file_size, sizeof(int), 0);
perror("1.25");
file_desc = open(file_name, O_CREAT | O_EXCL | O_WRONLY, 0666);
perror("1.5");
int incomingSize;
while((incomingSize = readn(socket, buff, sizeof(buff))) > 0)
{
perror("2 ");
for(int i = 0; i <= sizeof(buff); i++)
{
buff[incomingSize] = '\0';
write(file_desc, buff, sizeof(buff));
}
}
perror("3");
if(incomingSize < 0)
{
perror("Something went wrong connection broken");
return; // connection broken down
}
else
{
fprintf(stderr, "Connection terminated");
}
perror("4");
close(socket);
/*
perror("1");
data = malloc(BUFSIZ);
file_desc = open(file_name, O_CREAT | O_EXCL | O_WRONLY, 0777);
perror("1.2");
fprintf(stderr, "fileDesc = %d", file_desc);
perror("1.5");
strcpy(server_response, "OK");
write(socket, server_response, strlen(server_response));
perror("2");
//recv(socket, &file_size, sizeof(int), 0);
perror("3");
//recv(socket, &file_size, sizeof(int), 0);
file_size = BUFSIZ;
perror("4");
fprintf(stderr, "%d", file_size);
recv(socket, data, file_size, 0);
perror("5");
write(file_desc, data, file_size);
perror("6");
close(file_desc);
*/
/*// Start receiving file
if (strcmp(reply_msg, "OK") == 0) //Check that response is "OK"
{
}
else
{
fprintf(stderr, "Bad request\n");
}
*/
}
free(socket_desc);
return 0;
}
char* GetFilenameFromRequest(char* request)
{
char *file_name = strchr(request, ' ');
return file_name + 1;
}
bool SendFileOverSocket(int socket_desc, char* file_name)
{
struct stat obj;
int file_desc,
file_size;
stat(file_name, &obj);
file_desc = open(file_name, O_RDONLY);
file_size = obj.st_size;
send(socket_desc, &file_size, sizeof(int), 0);
sendfile(socket_desc, file_desc, NULL, file_size);
return true;
}
Client
/*
* Compile & link : gcc client.c -o client
* Execute : ./client
*
*/
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define FILENAME "a.txt" //Possibly worth changing to make it more dynamic
//Should consider overriding this with command line arguments if passed
#define SERVER_IP "127.0.0.1" //Address of local host
#define SERVER_PORT 8080
bool SendFileOverSocket(int socket_desc, char* file_name);
int writen(int fd, char *buf, int nbytes)
{
short data_size = nbytes; // short must be two bytes long
int n, nw;
if (nbytes > BUFSIZ)
return (-3); // too many bytes to send in one go
// send the data size
data_size = htons(data_size);
if (write(fd, (char *) &data_size, 1) != 1)
return (-1);
if (write(fd, (char *) (&data_size)+1, 1) != 1)
return (-1);
// send nbytes
for (n=0; n<nbytes; n += nw)
{
if ((nw = write(fd, buf+n, nbytes-n)) <= 0)
return (nw); // write error
}
return (n);
}
int main(int argc , char **argv)
{
int socket_desc;
// Variables for the file being received
int file_size, file_desc;
struct sockaddr_in server;
char request_msg[BUFSIZ],
reply_msg[BUFSIZ],
userCommand[BUFSIZ],
userFileName[BUFSIZ],
*data;
socket_desc = socket(AF_INET, SOCK_STREAM, 0);
if (socket_desc == -1)
{
perror("Could not create socket");
return 1;
}
server.sin_addr.s_addr = inet_addr(SERVER_IP);
server.sin_family = AF_INET;
server.sin_port = htons(SERVER_PORT);
// Connect to server
if (connect(socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0)
{
perror("Connection failed");
return 1;
}
printf("------------Enter Command-----------\n");
printf("Get, Put, Pwd, lpwd, dir, ldir, cd, lcd, quit\n");
printf("------------------------------------\n");
while(userCommand != "quit")
{
printf(">");
fgets(userCommand, BUFSIZ, stdin);
printf("User Command Variable = %s", userCommand);
if(strstr(userCommand, "Get"))
{
char userFileName[BUFSIZ];
// Get a file from server
strcpy(request_msg, "Get "); //Copy message "Get " into variable request_msg
printf("Enter the file name you would like to send.");
scanf("%s", userFileName);
strcat(request_msg, userFileName); //Add the file name to the end of the varaible that is now "Get "
printf("1");
write(socket_desc, request_msg, strlen(request_msg)); //Changing this to fwrite produces same results with more warnings
printf("2");
recv(socket_desc, reply_msg, 2, 0); //Wait here for response
printf("3");
// Start receiving file
if (strcmp(reply_msg, "OK") == 0) //Check that response is "OK"
{
printf("4");
recv(socket_desc, &file_size, sizeof(int), 0);
printf("5");
data = malloc(file_size);
file_desc = open(userFileName, O_CREAT | O_EXCL | O_WRONLY, 0666);
recv(socket_desc, data, file_size, 0);
printf("6");
write(file_desc, data, file_size);
printf("7");
close(file_desc);
}
else
{
fprintf(stderr, "Bad request\n");
}
}
else if(strstr(userCommand, "Put"))
{
char server_response[BUFSIZ], buff[BUFSIZ];
struct stat obj;
fprintf(stderr,"What is the file name you would like to send?\n");
scanf("%s", userFileName);
fprintf(stderr,"File name entered was: %s", userFileName);
strcpy(request_msg, "Put "); //Copy message "Get " into variable request_msg
strcat(request_msg, userFileName); //Add the file name to the end of the varaible that is now "Get "
perror("1");
write(socket_desc, request_msg, strlen(request_msg)); //Changing this to fwrite produces same results with more warnings
perror("2");
stat(userFileName, &obj);
file_desc = open(userFileName, O_RDONLY);
file_size = obj.st_size;
perror("2.1");
strcpy(reply_msg, "OK");
perror("2.2");
//write(socket_desc, reply_msg, strlen(reply_msg));
perror("2.3");
perror("2.4");
perror("2.45");
writen(socket_desc, buff, sizeof(buff));
//SendFileOverSocket(socket_desc, userFileName);
perror("3");
close(socket_desc);
/*if (access(userFileName + 1, F_OK) != -1)
{
}
else {
printf("File doesnt exist with access code %d\n", access(userFileName, F_OK));
strcpy(reply_msg, "OK");
write(socket, reply_msg, strlen(reply_msg));
}*/
}
}
return 0;
}
/*bool SendFileOverSocket(int socket_desc, char* file_name)
{
struct stat obj;
int file_desc,
file_size;
stat(file_name, &obj);
file_desc = open(file_name, O_RDONLY);
file_size = obj.st_size;
printf("2.5");
printf("%s", file_name);
//send(socket_desc, &file_size, sizeof(int), 0);
printf("2.6");
perror("Pre");
sendfile(socket_desc, file_desc, NULL, file_size);
perror("sendfile");
printf("2.7");
return true;
}*/
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
So I have a char* called bufptr that is of size 512. Within the first couple of spots is the name of the file that I will be reading from and everything else after that is data.
ex. char* bufptr = {'f', 'o', 'o', '.', 'c', '\0', ...}
I did not initialize it like that but that is the general idea
After this I store the name of the file into a different file using strcpy
ex.
auto int i = 0;
while(*bufptr != '\0')
{
fname[i++] = *bufptr;
bufptr++;
}
bufptr++;
After that, I open up the file
What I am having problems with is the fwrite portion.
I tried writing fwrite(bufptr, 1, 512 - strlen(destString), fp)
but instead of
// ============================================================================
// File: fcclient.c (Fall 2017)
// ============================================================================
I got þ================================================
How would I correctly call fwrite so that I don't run into this issue or is it because I am not skipping over the null? Or does string have something before or after the null?
edit:
I added a loop to check over bufptr and got this as the output
fcclient.c▒▒▒▒▒▒▒▒▒▒id▒.N=▒C▒h▒▒▒.8▒▒l▒ ▒ ▒▒▒`▒ ▒P▒▒▒H▒
▒`▒djd▒▒dd▒▒#▒
▒#▒(▒d▒p▒▒jd▒▒▒▒▒Бd▒=======================================================================
// File: fcclient.c (Fall 2017)
// ============================================================================
// This program is a file transfer client. The user at the keyboard is pread a total of 1 bytes
this was the loop I used
auto int t = 0;
for(; t < 512; t+=)
if(*(bufptr + t) != '\0')
printf("%c", *(bufptr + t));
Here is the server code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
// prototypes
int CopyFile(int src_sock);
// defined constants
#define BUFLEN 512
#define SERVER_PORT 50004
#define TRUE 1
#define FALSE 0
// function prototypes
int CopyFile(int src_sock);
int main(void)
{
auto char buf[BUFLEN]; // local buffer
auto socklen_t client_addr_size; // used for call to accept
auto int client_socket; // used for call to accept
auto int server_socket; // used for call to socket
auto struct sockaddr_in client_address; // used for call to accept
auto struct sockaddr_in server_address; // used for call to bind
// greet the user
puts("Welcome to fcserver!");
puts("Waiting to recieve file from client...");
// create a socket for the server
server_socket = socket(AF_INET, SOCK_STREAM, 0);
// prepare the socket address structure for the server
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(SERVER_PORT);
// bind the server socket to an address, using the address structure
if(bind(server_socket, (struct sockaddr*) &server_address, sizeof(server_address)))
{
perror("server -- bind failed");
}
// put the server socket into a listening state
if(listen(server_socket, 5))
{
perror("server -- bind failed");
}
// let stdout know the server is waiting for a connection
puts("server waiting...");
// wait for an actual client connection (this will block)
client_addr_size = sizeof(server_address);
client_socket = accept(server_socket, (struct sockaddr*) &server_address, &client_addr_size);
CopyFile(client_socket);
// close the client and server sockets
close(client_socket);
close(server_socket);
return 0;
} // end of "main"
int CopyFile(int src_sock)
{
auto char buf[BUFLEN];
auto char *bufptr;
auto char fname[BUFLEN];
auto FILE* fptr;
auto int num_client_bytes;
auto unsigned long total_bytes = 0;
if(-1 == (num_client_bytes = recv(src_sock, bufptr, BUFLEN, 0)))
perror("server -- recv failed");
strcpy(fname, bufptr);;
auto int t = 0;
for(; t< num_client_bytes; t++)
{
if(*(bufptr + t) != '\0')
printf("%c", *(bufptr + t));
}
fptr = fopen(fname, "w");
auto int i = strlen(fname) +1;
bufptr += i;
total_bytes = fwrite(bufptr, sizeof(bufptr), 1, fptr);
printf("read a total of %lu bytes \n", total_bytes);
// loop and read the rest of the file from the client
do {
if(num_client_bytes == 0)
break;
printf("read a total of %d bytes \n", num_client_bytes);
total_bytes += fwrite(buf, 1, num_client_bytes, fptr);
} while (TRUE);
fclose(fptr);
printf("there were a total of %lu bytes written \n", total_bytes);
return TRUE;
} // end of "CopyFile"
Here is the client file
// ============================================================================
// File: fcclient.c (Fall 2017)
// ============================================================================
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/un.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#define BUFLEN 256
#define SERVER_PORT 50004
int main(void)
{
auto char buf[BUFLEN]; // general purpose buffer
auto int server_socket; // used for server socket
auto struct sockaddr_in server_address; // used for server address
auto char fname[BUFLEN]; // used for filename
auto char *bufptr; // used for heap block
auto FILE *fptr; // used for input file
auto int result; // used to check return values
auto long fileSize; // used to store file size
// greet the user
puts("Welcome to fcclient!");
// get the filename from stdin
printf("Please enter in the filename: ");
scanf("%s", fname);
// open the input file
fptr = fopen(fname, "r");
if(fptr == NULL)
{
printf("Sorry there was an error trying to locate the file. Please exit and try again \n");
return 0;
}
// get the size of the file
fseek(fptr, 0, SEEK_END);
fileSize = ftell(fptr);
fseek(fptr, 0, SEEK_SET);
// allocate a buffer to store the file in heap memory
bufptr = malloc(sizeof(char) * fileSize);
// create a socket to connect with the server
server_socket = socket(AF_INET, SOCK_STREAM, 0);
// setup a socket address structure to target the server
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(SERVER_PORT);
server_address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
printf("Currently connecting to server... \n");
// connect to the server
if(-1 == connect(server_socket, (struct sockaddr*) &server_address, sizeof(server_address)))
perror("client -- connect failed");
// send the filename to the server (include the NULL!)
if(-1 == send(server_socket, fname, BUFLEN, 0))
perror("client -- send failed");
// read the file into the allocated buffer
fseek(fptr, sizeof(bufptr),SEEK_SET);
if(0 == fread(bufptr, sizeof(bufptr), fileSize, fptr))
{
printf("There was an error sorry. \n");
return 0;
}
// send the data to the server
if(-1 == send(server_socket, bufptr, fileSize, 0))
perror("client -- send failed");
// close the input file and the sockets
fclose(fptr);
close(server_socket);
return 0;
} // end of "main"
bufptr is not pointing to the content of the buffer,Because of bufptr += strlen(destString) , Its pointing to the location next to the content. Update the value of bufptr to point to the content you actually want to write.
There are two sets of problems in the code (some of them diagnosed in comments made to question). First, you write a full length buffer even though it contains mostly junk, and then you try to interpret that as part of the file, but it isn't. And second, you're playing with an uninitialized variable in the client file copy code — you're (un)lucky it didn't crash.
This code works.
fcserver.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define BUFLEN 512
#define SERVER_PORT 50004
void CopyFile(int src_sock);
int main(void)
{
socklen_t client_addr_size;
int client_socket;
int server_socket;
struct sockaddr_in server_address;
puts("Welcome to fcserver!");
puts("Waiting to recieve file from client...");
server_socket = socket(AF_INET, SOCK_STREAM, 0);
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(SERVER_PORT);
if (bind(server_socket, (struct sockaddr *)&server_address, sizeof(server_address)))
{
perror("server -- bind failed");
}
if (listen(server_socket, 5))
{
perror("server -- bind failed");
}
puts("server waiting...");
client_addr_size = sizeof(server_address);
client_socket = accept(server_socket, (struct sockaddr *)&server_address, &client_addr_size);
CopyFile(client_socket);
close(client_socket);
close(server_socket);
return 0;
}
void CopyFile(int src_sock)
{
char buf[BUFLEN];
char fname[BUFLEN];
FILE *fptr;
int num_client_bytes;
unsigned long total_bytes = 0;
if (-1 == (num_client_bytes = recv(src_sock, fname, BUFLEN, 0)))
{
perror("server -- recv failed");
exit(1);
}
printf("File name: [%s]\n", fname);
fptr = fopen(fname, "w");
if (fname == 0)
{
perror(fname);
exit(1);
}
while ((num_client_bytes = recv(src_sock, buf, BUFLEN, 0)) > 0)
{
printf("read a total of %d bytes\n", num_client_bytes);
total_bytes += fwrite(buf, 1, num_client_bytes, fptr);
}
fclose(fptr);
printf("there were a total of %lu bytes written\n", total_bytes);
}
That's 85 lines, instead of 170-odd lines.
fcclient.c
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/un.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#define BUFLEN 256
#define SERVER_PORT 50004
int main(void)
{
int server_socket;
struct sockaddr_in server_address;
char fname[BUFLEN] = "";
char *bufptr;
FILE *fptr;
size_t fileSize;
puts("Welcome to fcclient!");
printf("Please enter in the filename: ");
scanf("%s", fname);
fptr = fopen(fname, "r");
if (fptr == NULL)
{
printf("Sorry there was an error trying to locate the file. Please exit and try again \n");
return 0;
}
fseek(fptr, 0, SEEK_END);
fileSize = ftell(fptr);
fseek(fptr, 0, SEEK_SET);
bufptr = malloc(sizeof(char) * fileSize);
server_socket = socket(AF_INET, SOCK_STREAM, 0);
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(SERVER_PORT);
server_address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
printf("Currently connecting to server... \n");
if (-1 == connect(server_socket, (struct sockaddr *)&server_address, sizeof(server_address)))
perror("client -- connect failed");
if (-1 == send(server_socket, fname, BUFLEN, 0))
perror("client -- send failed");
fseek(fptr, 0, SEEK_SET);
if (fileSize != fread(bufptr, sizeof(char), fileSize, fptr))
{
printf("There was an error sorry. \n");
return 0;
}
if (-1 == send(server_socket, bufptr, fileSize, 0))
perror("client -- send failed");
fclose(fptr);
close(server_socket);
return 0;
}
That's 68 lines instead of 170-odd lines.
Testing
It is crucial to run the server in a different directory from the client, else you could get files truncated. However, when I used a sub-directory junk containing a file animals19.c and ran the client in that directory, while the server ran in the parent directory, I got the output:
server window
$ ./fcserver
Welcome to fcserver!
Waiting to recieve file from client...
server waiting...
File name: [animals19.c]
read a total of 512 bytes
read a total of 292 bytes
there were a total of 804 bytes written
$
client window
$ ../fcclient
Welcome to fcclient!
Please enter in the filename: animals19.c
Currently connecting to server...
$ ls -l animals19.c ../animals19.c
-rw-r--r-- 1 jleffler staff 804 Dec 13 00:42 ../animals19.c
-rw-r--r-- 1 jleffler staff 804 Dec 3 21:54 animals19.c
$ diff animals19.c ../animals19.c
$
Oh, and at some point, you should note "i before e except after c" (so it is receive and not recieve). You should also note that perror() prints an error; it does not exit. Continuing after using perror() is usually wrong.
I know C language superficially. Actually, i need to write application using sockets client-server that verifies the existence of the file.
i have an example with sockets in which client send to server char 'A', server receive this char, increment it and send 'B' to client. client print result. i want to remake this example to my need. But it not so easy as i think, considering my knowledge.
I would really appreciate any help that you could offer me.
client:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
int sockfd;
int len;
struct sockaddr_un address;
int result;
char ch='A';
const char *filename = "/home/nikolay/test.txt";
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
address.sun_family = AF_UNIX;
strcpy(address.sun_path, "server_socket");
len = sizeof(address);
result = connect(sockfd, (struct sockaddr *)&address, len);
if(result == -1){
perror("oops : client");
exit(1);
}
//want to send filename to server
write(sockfd, &filename, sizeof(filename));
//want to receive result int value from server
read(sockfd, &result, sizeof(result));
if(result == 0){
printf("file %s\t exist\n", filename);
printf("result = %d\n", result);
}else{
printf("File %s\t not exist\n", filename);
printf("result = %d\n", result);
}
close(sockfd);
exit(0);
}
server:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
int server_sockfd, client_sockfd;
int server_len, client_len;
struct sockaddr_un server_address;
struct sockaddr_un client_address;
unlink("server_socket");
server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
server_address.sun_family = AF_UNIX;
strcpy(server_address.sun_path, "server_socket");
server_len = sizeof(server_address);
bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
listen(server_sockfd, 5);
while(1) {
char *filename;
printf("server waiting\n");
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd,(struct sockaddr *)&client_address, &client_len);
//read and write client data:
read(client_sockfd, &filename, sizeof(filename));
// how receive access to 'filename'?
int res = access(filename, F_OK);
//printf("filename = %s\n", filename);
printf("res = %d\n", res);
//send to client result check exist file
write(client_sockfd, &res, sizeof(res));
close(client_sockfd);
}
}
How i can send to server file's name (string), than server receive this string, check is this file exist and send result (int value) to the client?
Some changes, using recv and send.
client
send(sockfd, filename, strlen(filename), 0);
printf("client: send\n");
char* res;
recv(sockfd, res, strlen(res), 0);
printf("client: reseive\n");
if(strcasecmp(res, "1") == 0){
printf("file %s\t exist\n", filename);
}else if(strcasecmp(res, "-1") == 0){
printf("file %s\t not exist\n", filename);
}
server:
recv(client_sockfd, filename, strlen(filename), 0);
int res = access(filename, F_OK);
//printf("filename = %s\n", filename);
printf("res = %d\n", res);
//write(client_sockfd, &res, sizeof(res));
char* buffer;
snprintf (buffer, 10, "%d", res);
printf("convert to string: %s\n", buffer);
printf("buffer len: %d\n", strlen(buffer));
send(client_sockfd, buffer, strlen(buffer),0);
occured Segmentation fault error. Why did this can happened? Console:
./client
client: send
res = -1
convert to string: -1
buffer len: 2
client: reseive
[1]+ Segmentation fault ./server
Some changes, using recv and send.
char* res;
recv(sockfd, res, strlen(res), 0);
occured Segmentation fault error. Why did this can happened?
res is not initialized, its value is indeterminate. Yet using this indeterminate value as an argument to strlen() is faulty. Let's discard the failed changes and get your working example to work.
client:
const char *filename = "/home/nikolay/test.txt";
…
//want to send filename to server
write(sockfd, &filename, sizeof(filename));
Here not the file name characters are sent, but a pointer to them, which is meaningless in the address space of the server. Simple fix:
const char filename[] = "/home/nikolay/test.txt";
server:
#include <limits.h>
char filename[PATH_MAX];
The comment from alk Dec 28 '13 at 15:21 is also noteworthy.
I am trying to implement a simple HTTP server with C that
reads a request
checks if it is a GET request
reads the URL from the request
Checks if file is on server and tries to open it
I am using strtok for String tokenizing and I think it messes up the filepath. open and fopen always return error codes and are not able to open any files.
Here is my code:
/*
** parser.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MYPORT 3499 // the port users will be connecting to
#define BACKLOG 10 // how many pending connections queue will hold
#define MAXLEN 1024 //upper limit of the length of the string
int main(void)
{
char input[MAXLEN]; //the line that is read from the client
char * token1; //GET request
char * token2; //filepath
char tmpstring[MAXLEN]; //filesize
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd, file open on file_fd
struct sockaddr_in my_addr; // my address information
struct sockaddr_in their_addr; // connector's address information
int sin_size;
int yes=1;
int n; //the amount of read characters from the client
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
my_addr.sin_family = AF_INET; // host byte order
my_addr.sin_port = htons(MYPORT); // short, network byte order
my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
perror("bind");
exit(1);
}
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
while(1) { // main accept() loop
sin_size = sizeof(struct sockaddr_in);
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
perror("accept");
continue;
}
printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr));
n = readline(new_fd, input, MAXLEN); //n is the amount of read characters
if (n == -1) {
perror("Unable to read line");
}
//Check if it is a GET message
token1 = strtok(input," ");
if(strcmp(token1, "GET") != 0)
{
send(new_fd, "Bad request\n", 30, 0);
}
else
{
//Retrieve the file path
token2 = strtok(NULL, " ");
if(token2 == NULL)
{
send(new_fd, "File path not specified\n", 23, 0); //Check if filename is empty
}
send(new_fd, token2, strlen(token2), 0); //test
printf("%s", token2);
if(token2[0] == '/') //remove the initial slash
memmove(token2, token2 + 1, strlen(token2));
//char * path = "test.html"; //test line
//char * buff;
//int len = sprintf(buff, "1: %d 2: %d\n", strlen(token1), strlen(token2));
//send(new_fd, buff, len, 0);
//Check if file is on the server
if(open(token2, O_RDONLY) < 0) //Error opening file
{
if(errno == EACCES)
send(new_fd, "Access error\n", 30, 0);
else
send(new_fd, "Not existed\n", 30, 0);
}
else
{
FILE * requested_file = fopen(token2, "r");
if(requested_file == NULL) //
{
send(new_fd, "Error in fopen\n", 30, 0);
}
else
{
send(new_fd, "File found\n", 30, 0); //successful
}
fseek(requested_file, 0, SEEK_END); // move to the end of the file
int end= ftell(requested_file); // get the position of the end of file
int stringlen = sprintf(tmpstring, "file size: %d\n", end);
send(new_fd, tmpstring, stringlen, 0);
}
}
close(new_fd); //close connection
}
return 0;
}
//helper function for recieving text
int readline(int fd, char *buf, int maxlen)
{
int n, rc;
char c;
for (n = 1; n < maxlen; n++) {
if ((rc = read(fd, &c, 1)) == 1) {
*buf++ = c;
if (c == '\n')
break;
} else if (rc == 0) {
if (n == 1)
return 0; // EOF, no data read
else
break; // EOF, read some data
} else
return -1; // error
}
*buf = '\0'; // null-terminate
return n;
}
So I'm placing a test.html in the same folder as the server. Then im telnetting to localhost and port 3499. This is the output when entering GET /test.html:
/test.html
Not existed
rError in fopen
Connection closed by foreign host.
try opening "test.html" instead of "\test.html"
I'm trying to get a simple send and receive UDP program working, but I'm having a bit of trouble with saving the received data. As far as I can tell the data is being sent and received properly, as I've printed it out on both ends. Before I write the data to the file (if I just print out the received chunk) it doesn't have any extra characters, so I'm a bit lost as to where they are coming from.
When I append each chunk of received data to the file it adds a "^P^B^GÐ^?" after every chunk written. for example one of the chunks ended with "We, therefore^P^B^GÐ^?," instead of "We, therefore,".
Any help is appreciated, thanks in advance.
UPDATE:
I've seemed to have gotten things working semi-better, I'm now having an issue with it replacing the first character of every chunk with a null character, for example:
"^#N CONGRESS, July 4, 1776." instead of "IN CONGRESS, July 4, 1776."
It's doing this for the first char of every chunk received, I've tried multiple debug print statements but can't seem to figure out what the issue is.
Here is my Receive and Send functions:
void receiveFile() {
int addr_len, bytesRead;
char recvData[BUFSIZE]; // Buffer to store received data
struct sockaddr_in server_addr, client_addr;
// Set up struct to receive data from our port and address
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero), 8);
addr_len = sizeof (struct sockaddr);
printf("\nWaiting for data on port %d\n", port);
//Keep reading data from the socket
while (1) {
FILE *fp;
fp=fopen("dummyfile.txt", "ab");
memset(recvData, 0, BUFSIZE);
bytesRead = recvfrom(sock, recvData, BUFSIZE, 0,
(struct sockaddr *) &client_addr, &addr_len);
int x;
for(x = 0; x < bytesRead; x++) {
fputc(recvData[x], fp);
}
// Print out who we're receiving from and what we're recieving
printf("Receiving data from %s : %d\n", inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port));
fclose(fp);
}}
Here is the Send Function:
void sendFile() {
// Announce who we're sending data to
if(DEBUG) { printf("\nSending %s to %s:%d\n", filename, address, port); }
// Open file
FILE * file = fopen(filename, "rb");
if (file == NULL) {
perror("Invalid File\n");
exit(1);
}
// Get size of the file
fseek(file, 0, SEEK_END);
int filesize = ftell(file);
rewind(file);
int curPos = 0;
int dataSize = 0;
while(curPos < filesize) {
struct sockaddr_in server_addr;
struct hostent *recvr;
char sendData[BUFSIZE]; // stores message to be sent
memset(sendData, 0, BUFSIZE);
int byte, i;
for(i = 0; i < BUFSIZE; i++){
if((filesize - curPos) > 0) {
byte = fgetc(file);
sendData[i] = byte;
curPos++;
dataSize++;
}
else { break; }
}
recvr = gethostbyname(address);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr = *((struct in_addr *) recvr->h_addr);
bzero(&(server_addr.sin_zero), 8);
if(DEBUG) {
char tempData[1201];
strncpy(tempData, sendData, 1200);
tempData[1201] ='\0';
printf("%s\n\n\n\n\n", tempData);
}
sendto(sock, sendData, dataSize, 0,
(struct sockaddr *) &server_addr, sizeof (struct sockaddr));
dataSize = 0;
}
fclose(file);}
What happens when you change the printing to:
fprintf(fp, "%.*s", bytesRead, recvData);
There is a guarantee that recvfrom() will not null terminate your messages; you would have to transmit the null terminator yourself.
I can't tell what your residual problem is. I have the following to complete programs working back to back. I've scrutinized the saved file for NULs with no problem.
I ran them as:
./recv & sleep 1; ./send; kill %1
recv.c
#include "posixver.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h> /* sockaddr_in */
#include <arpa/inet.h> /* inet_ntoa() */
#include "stderr.h"
static void receiveFile(int sock, int port, char *filename)
{
//Keep reading data from the socket
FILE *fp = fopen(filename, "ab");
if (fp == 0)
err_syserr("failed to open file %s", filename);
printf("\nWaiting for data on port %d\n", port);
while (1)
{
char recvData[BUFSIZ]; // Buffer to store received data
struct sockaddr_storage addr;
struct sockaddr_in *client_addr = (struct sockaddr_in *)&addr;
memset(recvData, 0, sizeof(recvData));
socklen_t addr_len = sizeof (struct sockaddr_storage);
int bytesRead = recvfrom(sock, recvData, sizeof(recvData), 0,
(struct sockaddr *) &client_addr, &addr_len);
if (bytesRead < 0)
err_syserr("Failed to read from socket");
err_remark("Read %d bytes\n", bytesRead);
for (int x = 0; x < bytesRead; x++)
{
fputc(recvData[x], fp);
}
fflush(fp);
// Print out who we're receiving from and what we're receiving
//char *rem_host = inet_ntoa(client_addr->sin_addr);
//int rem_port = ntohs(client_addr->sin_port);
//printf("Receiving %d bytes from %s:%d\n", bytesRead, rem_host ? rem_host : "<unknown>", rem_port);
}
fclose(fp);
}
int main(int argc, char **argv)
{
int fd;
struct sockaddr_storage addr;
struct sockaddr_in *server_addr = (struct sockaddr_in *)&addr;
memset(&addr, 0, sizeof(addr));
server_addr->sin_family = AF_INET;
server_addr->sin_addr.s_addr = htonl(INADDR_ANY);
server_addr->sin_port = htons(5190);
err_setarg0(argv[0]);
if (argc > 1)
err_usage("");
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
err_syserr("Failed to open DGRAM socket");
if (bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) != 0)
err_syserr("Failed to bind DGRAM socket");
receiveFile(fd, 5190, "dummy.text");
return(0);
}
send.c
#include "posixver.h"
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "stderr.h"
#define bzero(b,len) (memset((b), '\0', (len)), (void)0)
enum { DEBUG = 1 };
static void sendFile(int sock, const char *filename, char *address, int port)
{
// Announce who we're sending data to
if (DEBUG)
printf("\nSending %s to %s:%d\n", filename, address, port);
// Open file
FILE * file = fopen(filename, "rb");
if (file == 0)
err_syserr("Failed to open file %s", filename);
// Get size of the file
fseek(file, 0, SEEK_END);
int filesize = ftell(file);
rewind(file);
int curPos = 0;
int dataSize = 0;
while (curPos < filesize)
{
struct sockaddr_in server_addr;
struct hostent *recvr;
char sendData[BUFSIZ]; // stores message to be sent
memset(sendData, 0, BUFSIZ);
int byte, i;
for (i = 0; i < BUFSIZ; i++){
if ((filesize - curPos) > 0) {
byte = fgetc(file);
sendData[i] = byte;
curPos++;
dataSize++;
}
else
break;
}
recvr = gethostbyname(address);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr = *((struct in_addr *) recvr->h_addr_list[0]);
bzero(&(server_addr.sin_zero), 8);
if(DEBUG) {
char tempData[1201];
strncpy(tempData, sendData, 1200);
tempData[1201] ='\0';
printf("SEND:\n%s\n\n\n", tempData);
}
if (sendto(sock, sendData, dataSize, 0,
(struct sockaddr *) &server_addr, sizeof (struct sockaddr)) < 0)
err_syserr("Failed to send %d bytes\n", dataSize);
dataSize = 0;
}
fclose(file);
}
int main(int argc, char **argv)
{
int fd;
err_setarg0(argv[0]);
if (argc > 1)
err_usage("");
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
err_syserr("Failed to open DGRAM socket");
sendFile(fd, "/etc/passwd", "localhost", 5190);
return(0);
}
posixver.h
#ifndef JLSS_ID_POSIXVER_H
#define JLSS_ID_POSIXVER_H
/*
** Include this file before including system headers. By default, with
** C99 support from the compiler, it requests POSIX 2001 support. With
** C89 support only, it requests POSIX 1997 support. Override the
** default behaviour by setting either _XOPEN_SOURCE or _POSIX_C_SOURCE.
*/
/* _XOPEN_SOURCE 700 is loosely equivalent to _POSIX_C_SOURCE 200809L */
/* _XOPEN_SOURCE 600 is loosely equivalent to _POSIX_C_SOURCE 200112L */
/* _XOPEN_SOURCE 500 is loosely equivalent to _POSIX_C_SOURCE 199506L */
#if !defined(_XOPEN_SOURCE) && !defined(_POSIX_C_SOURCE)
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600 /* SUS v3, POSIX 1003.1 2004 (POSIX 2001 + Corrigenda) */
#else
#define _XOPEN_SOURCE 500 /* SUS v2, POSIX 1003.1 1997 */
#endif /* __STDC_VERSION__ */
#endif /* !_XOPEN_SOURCE && !_POSIX_C_SOURCE */
#endif /* JLSS_ID_POSIXVER_H */
stderr.c and stderr.h
Actually, not standard at all, except in my code. The functions used have the declarations:
extern void err_setarg0(const char *argv0);
extern void err_error(const char *format, ...) PRINTFLIKE(1,2) NORETURN();
extern void err_remark(const char *format, ...) PRINTFLIKE(1,2);
extern void err_syserr(const char *format, ...) PRINTFLIKE(1,2) NORETURN();
extern void err_usage(const char *usestr) NORETURN();
The first records the program name. The second reports an error message and exits; the third reports a message and returns; the fourth reports an error message and adds error information from 'errno' and 'strerror()' if there is any to use; the last reports on how to use the program - in this case, the programs accept no arguments. The full source code (quite large) is available from the IIUG Software site as part of the SQLCMD package available there, and various other programs that I've also submitted there.