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.
Related
I work on the server side Socket (use Telnet client) in Linux. Client input a line with command(GET/PUT/DEL, key and an associated value (spaces to seperate in between). This key-value pair is then passed accordingly on to the function(GET/PUT/DEL), which saves the data in the shared memory (keyValueStore).
Expected client side: (> is the output from Server)
GET key1
> GET:key1:key_nonexistent
PUT key1 value1
> PUT:key1:value1
PUT key2 value2
> PUT:key2:value2
DEL key2
> DEL:key2:key_deleted
Questions:
1/ i tried to use strtok() and keyValueStore to seperate & save the tokens in a normal c file, but how should I do (or transform) it into the data transfer communication between server and client?
2/ when or where should I call the command functions (e.g. int put(char* key, char* value) )? in server.c after reading the input but before giving output?
Any advices is appreicated. Thanks for your kindness!
server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define BUFSIZE 1024 // Buffer Size
#define TRUE 1
#define PORT 5678
int main() {
int rfd; // Create-Descriptor
int cfd; // Connection-Descriptor (accept)
struct sockaddr_in client;
socklen_t client_len;
char in[BUFSIZE];
int bytes_read;
// 1. socket()
rfd = socket(AF_INET, SOCK_STREAM, 0);
if (rfd < 0 ){
fprintf(stderr, "Error\n");
exit(-1);
}
//Initialize the server address by the port and IP
struct sockaddr_in server;
memset(&server, '\0', sizeof(server));
server.sin_family = AF_INET; // Internet address family: v4 address
server.sin_addr.s_addr = INADDR_ANY; // Server IP address
server.sin_port = htons(PORT); // Server port
// 2. bind()
int brt = bind(rfd, (struct sockaddr *) &server, sizeof(server));
if (brt < 0 ){
fprintf(stderr, "Error\n");
exit(-1);
}
// 3. listen() = listen for connections
int lrt = listen(rfd, 5);
if (lrt < 0 ){
fprintf(stderr, "Error\n");
exit(-1);
}
while (1) {
// 4. accept()
cfd = accept(rfd, (struct sockaddr *) &client, &client_len);
// read() = read from a socket (Client's data)
bytes_read = read(cfd, in, BUFSIZE);
while (bytes_read > 0) {
printf("sending back the %d bytes I received...\n", bytes_read);
// write() = write data on a socket (Client's data)
write(cfd, in, bytes_read);
bytes_read = read(cfd, in, BUFSIZE);
}
close(cfd);
}
close(rfd);
}
Input.c
#include <stdio.h>
#include <string.h>
#include <stdio.h>
#define MAX_ARRAY 100
int main() {
typedef struct Value_ {
char key[MAX_ARRAY];
char value[MAX_ARRAY];
} KeyStorage;
KeyStorage storageKey[MAX_ARRAY];
char client_input[MAX_ARRAY];
char *argv[3];
char *token;
int count = 0;
while (1) {
printf("Input: ");
gets(client_input);
//get the first token
token = strtok(client_input, " ");
int i = 0;
//walk through other tokens
while (token != NULL) {
argv[i] = token;
i++;
token = strtok(NULL, " ");
}
argv[i] = NULL; //argv ends with NULL
// arg[0] = command z.B. GET, PUT
printf("Commend: %s\n", argv[0]);
strcpy(storageKey[count].key, argv[1]);
printf("Key: %s\n", storageKey[count].key);
strcpy(storageKey[count].value, argv[2]);
printf("Value: %s\n", storageKey[count].value);
count++;
if (strcmp(argv[0], "QUIT") == 0) {
break;
}
}
return 0;
}
There are a number of errors in your code. I have fixed all to build a working example. Of course, this is not your complete application and there is even a lot of room for enhancements.
I developed and tested my code with MSVC2019 under Windows but I used a #define to isolate Windows specific code so it should compile and run correctly under Linux as well (I have not tested that).
The main problem your code had is a misunderstanding of TCP connection. It is a stream oriented connection and you must assemble "command lines" yourself, receiving one character at a time.
It is only when a line is complete that you can parse it to detect the command sent by the client. I made simple: only one command "exit" does something (close the connection). Everything else is simply ignored.
I made line assembling the easy way. That means that there is no edit possible. Backspace, delete, cursor keys and more and input as any other characters and doesn't work a a user would expect. You should take care of that.
Finally, I kept the code close to what you used. This code is single user. It accept a connection, accept commands from it and only accept a new connection once the first is closed. This is not normally the way to create a server program. To make it multiuser, you should use non-blocking socket and select() or use multi-threading.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#ifdef WIN32
#include <WinSock2.h>
#include <io.h>
typedef int socklen_t;
#pragma warning(disable : 4996) // No warning for deprecated function names such as read() and write()
#else
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define closesocket close
#endif
#define BUFSIZE 1024 // Buffer Size
#define TRUE 1
#define PORT 5678
int main(int argc, char *argv[])
{
#ifdef WIN32
int iResult;
WSADATA wsaData;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
#endif
int rfd; // Create-Descriptor
int cfd; // Connection-Descriptor (accept)
struct sockaddr_in client;
socklen_t client_len;
char in[BUFSIZE];
int bytes_read;
// 1. socket()
rfd = socket(AF_INET, SOCK_STREAM, 0);
if (rfd < 0) {
fprintf(stderr, "Error\n");
exit(-1);
}
// Initialize the server address by the port and IP
struct sockaddr_in server;
memset(&server, '\0', sizeof(server));
server.sin_family = AF_INET; // Internet address family: v4 address
server.sin_addr.s_addr = INADDR_ANY; // Server IP address
server.sin_port = htons(PORT); // Server port
// 2. bind()
int brt = bind(rfd, (struct sockaddr*)&server, sizeof(server));
if (brt < 0) {
fprintf(stderr, "Error\n");
exit(-1);
}
// 3. listen() = listen for connections
int lrt = listen(rfd, 5);
if (lrt < 0) {
fprintf(stderr, "Error\n");
exit(-1);
}
while (1) {
client_len = sizeof(client);
cfd = accept(rfd, (struct sockaddr*)&client, &client_len);
if (cfd < 0) {
fprintf(stderr, "accept failed with error %d\n", WSAGetLastError());
exit(-1);
}
printf("Client connected\n");
while (1) {
/*
// Send prompt to client
char* prompt = "> ";
if (send(cfd, prompt, strlen(prompt), 0) <= 0) {
fprintf(stderr, "send() failed with error %d\n", WSAGetLastError());
exit(1);
}
*/
// read a line from a socket (Client's data)
int bytes_idx = -1;
while (1) {
if (bytes_idx >= (int)sizeof(in)) {
fprintf(stderr, "input buffer overflow\n");
break;
}
// Receive on byte (character) at a time
bytes_read = recv(cfd, &in[++bytes_idx], 1, 0);
if (bytes_read <= 0) // Check error or no data read
break;
/*
printf("sending back the %d bytes I received...\n", bytes_read);
if (send(cfd, &in[bytes_idx], 1, 0) <= 0) {
fprintf(stderr, "send() failed with error %d\n", WSAGetLastError());
exit(1);
}
*/
if (in[bytes_idx] == '\n') {
// Received a complete line, including CRLF
// Remove ending CR
bytes_idx--;
if ((bytes_idx >= 0) && (in[bytes_idx] == '\r'))
in[bytes_idx] = 0;
break;
}
}
if (bytes_idx > 0) { // Check for empty line
printf("Received \"%s\"\n", in);
// Check for client command
if (stricmp(in, "exit") == 0)
break;
else {
printf("Client sent unknown command\n");
}
}
}
closesocket(cfd);
printf("Client disconnected\n");
}
closesocket(rfd);
#ifdef WIN32
WSACleanup();
#endif
}
I am trying to receive a file thats uploaded by the client and in the same socket descriptor send a command download a file from the server in chunks
The issue is if the socket descriptors are in different files things work flawlessly but if its the same file client and server programs are hanging up
The second problem is even if its in different files I could not send the client a message saying that the file is received
Can anyone please advice
PS- to run the program might need to create a file named fileclient.txt and enter some random text
server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#define PORT 8088
int main(void){
int fd =0, confd = 0,b,tot;
struct sockaddr_in serv_addr;
char buff[1025];
fd = socket(AF_INET, SOCK_STREAM, 0);
printf("Socket created\n");
memset(&serv_addr, '0', sizeof(serv_addr));
memset(buff, '0', sizeof(buff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(PORT);
bind(fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(fd, 10);
while(1){
confd = accept(fd, (struct sockaddr*)NULL, NULL);
if (confd==-1) {
perror("Accept");
continue;
}
//READ COMMAND reads first 4 characters of the buffer
int bf = recv(confd, buff, 1024,0);
char *filecmd = malloc(5 * sizeof(char));
memcpy(filecmd, buff, 4);
filecmd[4] = 0; //string termination
//if command is DOWN send chunks to the client
if(strcmp(filecmd, "DOWN") == 0){
int bt;
char sendbuffer[100];
FILE *fpdl = fopen("file.txt", "rb");
if(fpdl == NULL){
perror("File");
return 2;
}
while( (bt = fread(sendbuffer, 1, sizeof(sendbuffer), fpdl))>0 ){
send(confd, sendbuffer, bt, 0);
}
fclose(fpdl);
}
//if DOWN did not match that means client is uploading a file write down the file on server
else{
FILE* fp = fopen( "newfile.txt", "wb");
tot=0;
tot+=bf;
fwrite(buff, 1, bf, fp);
if(fp != NULL){
while( (b = recv(confd, buff, 1024,0))> 0 ) {
tot+=b;
fwrite(buff, 1, b, fp);
}
printf("Received byte: %d\n",tot);
if (b<0) perror("Receiving Error");
fclose(fp);
} else {
perror("File");
}
}
free(filecmd);
close(confd);
}
return 0;
}
client.c
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#define PORT 8088
int main(int argc, char *argv[]){
int sfd =0, n=0, b;
char sendbuffer[100];
struct sockaddr_in serv_addr;
sfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
b=connect(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (b==-1) {
perror("Connect");
return 1;
}
FILE *fp = fopen("fileclient.txt", "rb");
if(fp == NULL){
perror("File");
return 2;
}
while( (b = fread(sendbuffer, 1, sizeof(sendbuffer), fp))>0 ){
send(sfd, sendbuffer, b, 0);
}
fclose(fp);
char *rpccommand = "DOWN";
send(sfd , rpccommand , strlen(rpccommand) , 0 );
char buffer[1024] = {0};
FILE* fpx = fopen( "downloadfile.txt", "wb");
int tot=0, bn;
if(fpx != NULL){
while( (bn = recv(sfd, buffer, 1024,0))> 0 ) {
tot+=bn;
fwrite(buffer, 1, bn, fpx);
}
printf("Received byte: %d\n",tot);
if (bn<0) perror("Receiving");
fclose(fpx);
} else {
perror("File");
}
return 0;
}
You seem to expect that the string "DOWN" is recognized by the server and a download is triggered. This is very unlikely to happen.
TCP connections do not take care about granularity of data that is put into the socket. If you put in 1000 bytes at once on one side, it is not guaranteed that those 1000 bytes are received in one go.
You may receive either 1000 bytes or 500 + 500 bytes of 999 + 1 bytes.
Same applies if you send with multiple requests. Putting in 1000+4 bytes could result in receiving 1000+4 or 1004 or 500+500+4 bytes or any other combination.
This means that you cannot simply rely on receiving all bytes for the file upload first and then wait for another command ("DOWN") or another file. It is very likely that you will receive the "DOWN" together with the last bytes of the uploaded file and simply store them into the output file.
The same applies for download direction. The client would not be able to distinguish a file download from an "upload done" notification.
To solve your problem you need to introduce more logic into your protocol. There are various options:
Use 1 socket and 1 connection for each operation or each direction. No need to mix everything into a single socket.
Add some indication about file upload, e.g. total length to be expected in front of your upload.
Use 1 socket for control flow and multiple others for data transfer (see FTP for details)
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.
I am trying to write a file transfer program using threading. The format I am trying to follow is:
./server 4501 ..................(will run forever)
./client 4501 add1.txt
./client 4501 bdd1.txt
And add1.txt and bdd1.txt will save in server side as add2.txt and bdd2.txt. But after running my code I found that add2.txt contains the characters from add1.txt plus some extra characters.
**
Updated Solution
**
Server Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pthread.h>
#include <unistd.h>
/* Preprocessor Directives */
#define NTHREADS 50
#define QUEUE_SIZE 5
#define BUFFER_SIZE 256
/* Global counter locked via mutex */
pthread_t threadid[NTHREADS]; // Thread pool
pthread_mutex_t lock;
int counter = 0;
void *threadworker(void *arg)
{
int sockfd, rw; // File descriptor and 'read/write' to socket indicator
char *buffer; // Message buffer
sockfd = (int) arg; // Getting sockfd from void arg passed in
buffer = malloc(BUFFER_SIZE);
bzero(buffer, BUFFER_SIZE);
rw = read(sockfd, buffer, BUFFER_SIZE); // Blocks until there is something to be read in the socket
FILE *fp;
fp=fopen("add2.txt","w");
fprintf(fp,"%s",buffer);
//fwrite(buffer, strlen(buffer) + 1, 1, fp);
//fwrite(buffer,sizeof(char),BUFFER_SIZE, fp);
fclose(fp);
printf("%d\n",strlen(buffer));
printf("the file was received successfully\n");
printf("the new file created is add2.txt\n");
if (rw < 0)
{
perror("Error reading form socket, exiting thread");
pthread_exit(0);
}
//printf("New message received: %s", buffer); // String already has newline
bzero(buffer, BUFFER_SIZE);
//sprintf(buffer, "Acknowledgement from TID:0x%x", pthread_self());
/*rw = write(sockfd, buffer, strlen(buffer));
if (rw < 0)
{
perror("Error writing to socket, exiting thread");
pthread_exit(0);
}*/
/* Critical section */
/*printf("Requesting mutex lock...\n");
pthread_mutex_lock (&lock);
printf("Current counter value: %d, upping by 1...\n", counter);
counter++;
pthread_mutex_unlock (&lock);
printf("Done! Mutex unlocked again, new counter value: %d\n", counter);
*/
close(sockfd);
//printf("TID:0x%x served request, exiting thread\n", pthread_self());
pthread_exit(0);
}
int main(int argc, char *argv[])
{
/* Variable declarations */
int serv_sockfd, new_sockfd; //Socket identifiers for server and incoming clients
struct addrinfo flags; // Params used to establish listening socket
struct addrinfo *host_info; // Resultset for localhost address info, set by getaddrinfo()
socklen_t addr_size; // Client address size since we use sockaddr_storage struct to store
// client info coming in, not using addrinfo as done for host (local)
// by calling getaddrinfo for resolution, which stores results in
// the more convenient addrinfo struct
struct sockaddr_storage client; // Sockaddr storage struct is larger than sockaddr_in,
// can be used both for IPv4 and IPv6
pthread_attr_t attr; // Thread attribute
int i; // Thread iterator
/* Start of main program */
if (argc < 2) {
fprintf(stderr,"Error: no port provided\n");
exit(-1);
}
memset(&flags, 0, sizeof(flags));
flags.ai_family = AF_UNSPEC; // Use IPv4 or IPv6, whichever
flags.ai_socktype = SOCK_STREAM; // TCP
flags.ai_flags = AI_PASSIVE; // Set address for me
if (getaddrinfo(NULL, argv[1], &flags, &host_info) < 0)
{
perror("Couldn't read host info for socket start");
exit(-1);
}
serv_sockfd = socket(host_info->ai_family, host_info->ai_socktype, host_info->ai_protocol);
if (serv_sockfd < 0)
{
perror("Error opening socket");
exit(-1);
}
if (bind(serv_sockfd, host_info->ai_addr, host_info->ai_addrlen) < 0)
{
perror("Error on binding");
exit(-1);
}
freeaddrinfo(host_info); // Don't need this struct anymore
pthread_attr_init(&attr); // Creating thread attributes
pthread_attr_setschedpolicy(&attr, SCHED_FIFO); // FIFO scheduling for threads
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); // Don't want threads (particualrly main)
// waiting on each other
listen(serv_sockfd, QUEUE_SIZE); // Pass in socket file descriptor and the size of the backlog queue
// (how many pending connections can be in queue while another request
// is handled)
addr_size = sizeof(client);
i = 0;
while (1)
{
if (i == NTHREADS) // So that we don't access a thread out of bounds of the thread pool
{
i = 0;
}
new_sockfd = accept(serv_sockfd, (struct sockaddr *) &client, &addr_size);
if (new_sockfd < 0)
{
perror("Error on accept");
exit(-1);
}
pthread_create(&threadid[i++], &attr, &threadworker, (void *) new_sockfd);
sleep(0); // Giving threads some CPU time
}
return 0;
}
And the Client Code is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pthread.h>
#include <unistd.h>
#define BUFFER_SIZE 256
int main(int argc, char *argv[])
{
int sockfd, rw;
struct addrinfo flags;
struct addrinfo *server_info;
char *buffer = malloc(BUFFER_SIZE);
if (argc < 4)
{
fprintf(stderr, "Usage: ./client <hostname/address> <port> <file_path>");
exit(-1);
}
memset(&flags, 0, sizeof(flags)); // Clear so we're not working with garbage
flags.ai_family = AF_UNSPEC; // IPv4 or IPv6 doesn't matter
flags.ai_socktype = SOCK_STREAM; // TCP
flags.ai_flags = AI_PASSIVE; // get the IP for me
if (getaddrinfo(argv[1], argv[2], &flags, &server_info) < 0) { // Resolve host based on CMD args
perror("Couldn't find host");
exit(-1);
}
sockfd = socket(server_info->ai_family, server_info->ai_socktype, server_info->ai_protocol); // Initialize socket
if (connect(sockfd, server_info->ai_addr, server_info->ai_addrlen) < 0)
{
perror("Couldn't conenct...");
exit(-1);
}
//printf("Connection established, please enter a message:\n");
bzero(buffer, BUFFER_SIZE);
//fgets(buffer, BUFFER_SIZE - 1, stdin);
//char buffer[100];
FILE *f;
size_t read=0;
if((f=fopen(argv[3],"r"))==NULL){
printf("Failed");
exit(-1);
}
//fseek(f, 0, SEEK_END);
//len = ftell(f);
//while (fgets(buffer, strlen(buffer), f) != NULL)
//fscanf(f,"%s",buffer);
//fread(buffer, strlen(buffer)+1, 1, f);
do{
read = fread(buffer,sizeof(char),BUFFER_SIZE-1, f);
if (read > 0) //if return value is > 0
{
buffer[BUFFER_SIZE]='\0';
rw = write(sockfd, buffer, strlen(buffer));
}
}
while(read == BUFFER_SIZE); //end when a read returned fewer items
fclose(f);
//write(sock, &len, sizeof(int));
//write(sock, buffer, len);
printf("the file was sent successfully");
//rw = write(sockfd, buffer, strlen(buffer)); // Sending the contents of the buffer - writes using socket file descriptor
if (rw < 0)
{
perror("Failed to send message");
exit(-1);
}
/*bzero(buffer, BUFFER_SIZE);
rw = read(sockfd, buffer, BUFFER_SIZE); // Read the ENTIRE buffer because we don't know stlen yet
if (rw < 0)
{
perror("Error reading from socket");
exit(-1);
}
printf("The message is: %s\n", buffer);
*/
close(sockfd);
return 0;
}
My add1.txt file contains
abcd
efgh
ijkl
mnop
The add2.txt file contains as output:
abcd
efgh
ijkl
mnop
############################################################################################################################################################################################################################################
Can anyone please advice me what are the modifications I will need then.
Thank you, in advance.
You need to call fclose on File *fp (server code) and File *f (client code) after you are done reading/writing the file. You did close the connection between the client and server, but you did not close the file stream which is probably the cause of the files being empty. So in your case it will be safe to call fclose after you called fprintf (server code) and fscanf (client code).
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.