I am trying to make a file transfer program with UDP, using a stop and wait protocol. The client prompts user to enter the text file to transfer and if exist, the server will find it and send it back in packets (80 char at a time). The part where the client sends the file name and the server receives it works, but once I get into the while(1) loop for the file transfer, nothing happens. Not sure why this is the case, any help will be great! thanks!
Client.c
`#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <errno.h>
/*This source file lies the client side of the file transfer. Its job is to open a
socket and ask to connect with server
It should then ask user for input of the text file they wish to transfer.
Once server sends out the file in packets, the client will then place this data in an
output.txt file, viewable for the user*/
typedef struct packet{
char pktData[80]; //data in each packet
}Packet;
typedef struct frame{
int frame_kind; //ACK:0, SEQ:1 FIN:2
int countOfChar; //count of characters in a packet
int sq_no;
int ack;
Packet packet;
}Frame;
int offset = 4;
int main(){
int sockfd = 0; //socket descriptor
int countOfChar = 0; //count of characters in a packet
char buffer[80]; //data in each packet
char fileName[20];
char pktData[80];
//socklen_t addr_size;
int frame_id = 0;
int frame_id2 = 0;
Frame frame_send; //frame being sent to server (for the filename)
Frame frame_recv; //frame being received from the server (for the data)
Frame name_send;
Frame name_recv;
int ack_recv = 1;
struct sockaddr_in serv_addr;
struct sockaddr_in new_addr;
memset(&serv_addr, '0', sizeof(serv_addr));
// Open a socket
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
printf("Error creating socket");
return 1;
}
// Server address structure
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(20000);
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
socklen_t addr_size = sizeof(serv_addr);
//Sending File name
printf("\nConnected to server successfully!\nEnter the file name: ");
scanf("%[^\n]%*c",fileName);
printf("\n");
char buff[20];
strcpy(buff, fileName);
sendto(sockfd, &buff, sizeof(buff), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
int new_addr_size = sizeof(new_addr);
//int addr_size = sizeof(serv_addr);
//writing file into output.txt
FILE *fp = fopen("output.txt", "ab");
//loop until theres no more to read
while(1){
int f_recv_size = recvfrom(sockfd, &frame_recv, sizeof(Frame), 0, (struct sockaddr*)&serv_addr, &addr_size);
if (f_recv_size > 0 && frame_recv.frame_kind == 1 && frame_recv.sq_no == frame_id){
fwrite(frame_recv.packet.pktData, 1, sizeof(frame_recv.packet.pktData), fp);
//printf("[+]Frame %d received with %lu data bytes\n",frame_recv.sq_no, sizeof(frame_recv.packet.pktData));
printf("Frame Received");
frame_send.sq_no = 0;
frame_send.frame_kind = 0;
frame_send.ack = frame_recv.sq_no + 1;
sendto(sockfd, &frame_send, sizeof(frame_send), 0, (struct sockaddr*)&serv_addr, addr_size);
printf("[+]Ack Sent\n");
}else{
printf("[+]Frame Not Received\n");
}
frame_id++;
}
close(sockfd);
return 0;
}
Server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/*This source file lies the server side of the file transfer. Its job is to listen
for a connection and connect with client when prompted.
It should then read the file with the txt file name and start sending out packets of
80 bytes each with the data of the given file name.*/
typedef struct packet{
char pktData[80]; //data in each packet
}Packet;
typedef struct frame{
int frame_kind; //ACK:0, SEQ:1 FIN:2
int countOfChar; //count of characters in a packet
int sq_no;
int ack;
Packet packet;
}Frame;
int main(){
unsigned int size = 0;
int listenfd = 0;
int connfd = 0;
char file_buff[20];
char buffer[80];
char FLAG[] = "NF"; //No file flag
int frame_id = 0;
int frame_id2 = 0;
Frame name_recv;
Frame name_send;
Frame frame_recv;
Frame frame_send;
int ack_recv;
struct sockaddr_in server_addr, client_addr;
char sendBuff[1025];
size = sizeof(client_addr);
listenfd = socket(AF_INET, SOCK_DGRAM, 0); //listening descriptor
printf("Server initiated...\n");
memset(&server_addr, '0', sizeof(server_addr));
memset(sendBuff, '0', sizeof(sendBuff));
//Local address structure
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(20000);
//bind to local address
bind(listenfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
// Receiving File Name
recvfrom(listenfd, &file_buff, sizeof(file_buff), 0, (struct sockaddr*)&client_addr, &size);
printf("Filename requested by client = %s\n",file_buff);
if (access(file_buff, F_OK) != -1 ) {
printf("File exist!\n");
FILE *fp = fopen(file_buff,"rb");
while(1){
if(ack_recv == 1){
frame_send.sq_no = frame_id;
frame_send.frame_kind = 1;
frame_send.ack = 0;
fscanf(fp, "%s ", buffer);
strcpy(frame_send.packet.pktData, buffer);
sendto(listenfd, &frame_send, sizeof(Frame), 0, (struct sockaddr*)&client_addr, sizeof(client_addr));
//printf("[+]Frame %d Sent with %lu data bytes\n",frame_send.sq_no, strlen(frame_send.packet.pktData));
printf("Frame Sent");
}
int addr_size = sizeof(server_addr);
int f_recv_size = recvfrom(listenfd, &frame_recv, sizeof(frame_recv), 0 ,(struct sockaddr*)&client_addr, &size);
if( f_recv_size > 0 && frame_recv.sq_no == 0 && frame_recv.ack == frame_id+1){
printf("[+]Ack Received\n");
ack_recv = 1;
}
else{
printf("[-]Ack Not Received\n");
ack_recv = 0;
}
frame_id++;
}
}
else {
printf("File doesn't exist\n");
write(listenfd, FLAG, sizeof(FLAG));
close(listenfd);
return 0;
}
close(listenfd);
return 0;
}
Sorry for all the clutter and unnecessary variables in advanced, I've been trying so many options but nothing's working.
Server's response in terminal
Client's response in terminal
The first problem is that you never initialize ack_recv in the server program before attempting to read it. Reading an uninitialized variable that hasn't had its address taken triggers undefined behavior.
At the very least, a value besides 1 was read so the server is waiting on a read from the client which never comes because the client is waiting on the server. You need to initialize ack_recv to 1 so that the server sends the first part of the file.
The code has more problems than this, however.
The main problem is it assumes that no packets get lost. UDP doesn't guarantee delivery. So if a packet does get lost, one side will be stuck forever waiting for a packet that doesn't arrive. When reading, each side should use select to allow for a timeout while waiting. If the timeout triggers, it should assume that the last packet sent was lost and resend it.
For the client, this also means that it can get multiple copies of a given sequence number from the server if an ACK gets lost. So it should not increment frame_id until it receives that sequence number.
There's also an infinite loop on both sides, as there is a while (1) loop with no break, return, or exit inside. The server needs to know when to stop sending, and it needs some way to let the client know when it's done.
Also, as a general rule, when debugging network programs you should use tcpdump or wireshark to trace the packets traveling in both directions.
Related
Both programs compile, and I'm able to successfully create a socket, but the connection to the server fails. This is basically a TCP echo program.
PS. I'm new here so IDK how to use this, I don't have much programming experience so bare with me.
tcp echo client-1
tcp echo client-2
tcp echo server-1
tcp echo server-2
Compiling/Running server gives me: Server not fully implemented...
Compiling/Running client gives me: Socket successfully created..Error: connection to the server failed!
**// TCP echo client program**
#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>
int main (int argc, char* argv[ ]) // Three arguments to be checked later
{
struct sockaddr_in servAddr; // Server socket address data structure
char *servIP = argv[1]; // Server IP address from command line
int servPort = atoi(argv[2]); // Server port number from command line
char *message = argv[3]; // Message specified on the command line
char buffer [512 + 1];
char* ptr = buffer;
int len;
int max_len = sizeof(buffer);
int sock_descrip;
// Check for correct number of command line arguments
if(argc != 4) {
printf("tcp-echo-client [IP address] [Port] [Message]\n");
exit (1);
}
// Populate socket address for the server
memset (&servAddr, 0, sizeof(servAddr)); // Initialize data structure
servAddr.sin_family = AF_INET; // This is an IPv4 address
servAddr.sin_addr.s_addr = inet_addr(servIP); // Server IP address
servAddr.sin_port = servPort; // Server port number
// Create a TCP socket stream
int sock;
if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
printf("Error: socket creation failed!\n");
exit (1);
}
else
printf("Socket successfully created..\n");
// Connect to the server
if ((connect (sock, (struct sockaddr*)&servAddr, sizeof(servAddr))) == -1) {
printf("Error: connection to the server failed!\n");
exit (1);
}
else
printf("Connected to the server..\n");
// Send data to the server...
send(sock_descrip, message, strlen(message),0);
int x;
while ((x = recv(sock_descrip, ptr, max_len,0))>0)
{
ptr += x;
max_len -= x;
len += x;
}
buffer[len] = '\0';
printf("Echoed string received: %s %c", buffer,*message);
// Receive data back from the server..
// Loop while receiving data...
// print data...
// end-while loop
// Close socket
close (sock);
// Stop program
exit (0);
} // End main
**//TCP Echo server program**
#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>
#define BUFLEN 512 // Maximum length of buffer
#define PORT 9988 // Fixed server port number
int main (void)
{
struct sockaddr_in server_address; // Data structure for server address
struct sockaddr_in client_address; // Data structure for client address
int client_address_len = 0;
char buffer [512];
char* ptr = buffer;
int len;
int max_len = BUFLEN;
int sock_descrip;
// Populate socket address for the server
memset (&server_address, 0, sizeof (server_address)); // Initialize server address data structure
server_address.sin_family = AF_INET; // Populate family field - IPV4 protocol
server_address.sin_port = PORT; // Set port number
server_address.sin_addr.s_addr = INADDR_ANY; // Set IP address to IPv4 value for loacalhost
// Create a TCP socket; returns -1 on failure
int listen_sock;
if ((listen_sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
printf("Error: Listen socket failed!\n");
exit (1);
}
// Bind the socket to the server address; returns -1 on failure
if ((bind(listen_sock, (struct sockaddr *)&server_address, sizeof (server_address))) == -1) {
printf("Error: binding failed!\n");
exit (1);
}
printf("Server not fully implemented...\n");
// Listen for connections...
int wait_size;
if (listen(listen_sock, wait_size) == -1)
{
printf("Error: listening failed!\n");
exit(1);
}
for(;;)
{
if(sock_descrip=accept(listen_sock,(struct sockaddr *)&client_address, &client_address_len) == -1)
{
printf("Error: accepting failed!\n");
exit(1);
}
int x;
while ((x = recv(sock_descrip, ptr, max_len, 0)) > 0)
{
ptr += x;
max_len -= x;
len += x;
}
send(sock_descrip,buffer,len,0);
}
// Echo data back to the client...
close (listen_sock); // Close descriptor referencing server socket
} // End main
You need parentheses around the assignment:
if(
(sock_descrip=accept(listen_sock,(struct sockaddr *)&client_address, &client_address_len))
== -1)
I have a simple server and client written in C.
They communicate well until the very end of my program where the server seems to skip the "read" method and just proceeds, it'll print out a blank line at
printf("%s", playAgain);
Here is the end of the code
#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 <netdb.h>
#include <arpa/inet.h>
#define BACKLOG 10
char invalidPortNumber[] = "Please specify a port number between 2000 and 65535";
char intro[] = "Welcome to the prisoners dilemma";
char playGame[] = "Will you stay silent or betray the other prisoner?\nType S for silent or B for betray";
char option1[] = "The other prisoner betrayed you\nYou each get 2 years in prison";
char option2[] = "The other prisioner betrayed you\nYou get 3 years in prison, the other prisioner is set free";
char option3[] = "The other prisioner stayed silent\nYou are set free, the other prisioner gets 3 years in prison";
char option4[] = "The other prisioner stayed silent\nYou both get 1 year on a lesser charge";
int main(int argc, char *argv[]) {
if (argc < 2) {
printf("Run with port number as the argument\n");
exit(1);
}
int port = atoi(argv[1]);
if (port<2000 || port>65535){
printf("%s\n", invalidPortNumber);
exit(2);
}
//Struct to store information for IPv4 address
struct sockaddr_in serverAddress;
//Create socket for IPv4, reliable stream (TCP), default protocol
int serverSocket = socket(PF_INET, SOCK_STREAM, 0);
//Specify that IPv4 family addresses will be used
serverAddress.sin_family = AF_INET;
//Set the port number
serverAddress.sin_port = htons(port);
//Bind to all local interfaces for IP
serverAddress.sin_addr.s_addr = INADDR_ANY;
//Bind the created socket to the IP address specified in the sockaddr_in struct
bind(serverSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress));
//Listen for connections, allowing backlog of up to BACKLOG connection requests
listen(serverSocket, BACKLOG);
int play = 0;
while(1) {
//Struct to store info of connecting clients
struct sockaddr_in clientAddress;
socklen_t clientAddrSize = sizeof(clientAddress);
//Create a socket for the connection between the client and server
int connectionSocket = accept(serverSocket, (struct sockaddr *) &clientAddress, &clientAddrSize);
//Input buffer to store client's request
do{
char input[800];
memset(input, '\0', sizeof(input));
//Have intro to the game
write(connectionSocket, intro, sizeof(intro) - 1);
//Read client's input
read(connectionSocket, input, sizeof(input)-1);
if(strcmp(input,"Y\n")==0||strcmp(input,"y\n")==0){
write(connectionSocket, playGame, sizeof(playGame) - 1);
}
else if(strcmp(input,"N\n")==0||strcmp(input,"n\n")==0){
write(connectionSocket, "Okay, connection closed", sizeof("Okay, connection closed") - 1);
close(connectionSocket);
return 0;
}
//read clients choice
char clientChoice[2];
read(connectionSocket, clientChoice, sizeof(clientChoice)-1);
srand(time(NULL));
int random = rand();
if( random % 2 ==0 ){
char serverChoice[2] = "S";
if(strcmp(clientChoice, "S")==0){
write(connectionSocket, option4, sizeof(option4) - 1);
}
else if(strcmp(clientChoice, "B")==0){
write(connectionSocket, option3, sizeof(option3) - 1);
}
}
else {
char serverChoice[2] = "B";
if(strcmp(clientChoice, "S")==0){
write(connectionSocket, option2, sizeof(option2) - 1);
}
else if(strcmp(clientChoice, "B")==0){
write(connectionSocket, option1, sizeof(option1) - 1);
}
}
char playAgain[5];
read(connectionSocket, playAgain, sizeof(playAgain)-1);
printf("%s",playAgain);
if(strcmp(playAgain, "Play")==0){
printf("Playing again");
play=1;
}
}while(play==1);
}
//Close the server socket and terminate the program if the loop ever ends
close(serverSocket);
return 0;
}
That is the server.
And now here is the end of the Client
#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 <netdb.h>
#include <arpa/inet.h>
#define BACKLOG 10
char invalidPortNumber[] = "Please specify a port number between 2000 and 65535";
char intro[] = "Welcome to the prisoners dilemma";
int main(int argc, char *argv[]) {
char buffer[512];
char IPAddress[15];
int n;
if (argc < 2) {
printf("Run with host IP and port number as the argument\n");
exit(1);
}
int port = atoi(argv[1]);
if (port<2000 || port>65535){
printf("%s\n", invalidPortNumber);
exit(2);
}
//Struct to store information for IPv4 address
struct sockaddr_in serverAddress;
//Create socket for IPv4, reliable stream (TCP), default protocol
int serverSocket = socket(PF_INET, SOCK_STREAM, 0);
//Specify that IPv4 family addresses will be used
serverAddress.sin_family = AF_INET;
//Set the port number
serverAddress.sin_port = htons(port);
//Bind to all local interfaces for IP
serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
//Bind the created socket to the IP address specified in the sockaddr_in struct
int play=0;
if(connect(serverSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress))<0){
printf("Couldn't connect, make sure the server is running and port number is correct \n");
return 1;
}
//read intro from server
do{
bzero(buffer,512);
n = read(serverSocket,buffer,511);
printf("%s\n",buffer);
//ask user if they'd like to play
int validCommand=1;
do{
printf("Would you like to play? (Y/N) ");
bzero(buffer,512);
fgets(buffer,511,stdin);
if(strcmp(buffer, "Y\n")==0||strcmp(buffer, "N\n")==0){
validCommand=0;
}
else{
printf("Invalid command \n");
}
}while(validCommand==1);
//write whether user wants to play to server
n = write(serverSocket,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,512);
//read response from server
n = read(serverSocket,buffer,511);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
if(strcmp(buffer, "Okay, connection closed")==0){
close(serverSocket);
return 0;
}
do{
bzero(buffer,512);
printf("Make your choice (B/S) ");
fgets(buffer,511,stdin);
if(strcmp(buffer, "B\n")==0||strcmp(buffer, "S\n")==0){
validCommand=0;
}
else{
printf("Invalid command \n");
validCommand=1;
}
}while(validCommand==1);
//write the users choice to the server
n = write(serverSocket,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,512);
n = read(serverSocket,buffer,511);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
do{
bzero(buffer,512);
printf("Would you like to play again? (Play/Quit) ");
fgets(buffer,511,stdin);
if(strcmp(buffer, "Play\n")==0||strcmp(buffer, "Quit\n")==0){
validCommand=0;
}
else{
printf("Invalid command \n");
validCommand=1;
}
}while(validCommand==1);
//write the users choice to the server
if(strcmp(buffer, "Quit\n")==0){
printf("Closing Connection to server");
close(serverSocket);
return 0;
}
if(strcmp(buffer, "Play\n")==0){
printf("Playing again");
play=1;
n = write(serverSocket,buffer,strlen(buffer)-1);
if (n < 0)
error("ERROR writing to socket");
}
}while(play==1);
}
Both the client and server work for the Choice B/S, the client sends, and the server responds. I have no idea what could be wrong, but the server seems to not wait for the clients final command
First, I think the basic problem you're running into is the common misconception that 1 write corresponds to 1 read automagically. It doesn't.
The problem you mention is caused by your reads and writes being out of sync. You need to make sure that you are reading the same amount as you send each time. The server isn't "proceeding without waiting to read client command;" it has just already read and ignored it.
For instance, when the client does
write(serverSocket, buffer, strlen(buffer))
the server is going to be confused. If you don't send over the size of the string first, the server can't know when to stop reading. This is especially true since you don't send the NUL-terminator. This specific problem could be avoided by doing more processing on the client side. By checking the input against "Y" and "N" on the client, you can simplify the communication to simply sending over a one byte boolean value. This reduces the complexity of your code and the amount of communication required between server and client.
If you would like examples of how you might start improving this, or have questions, just ask in the comments.
Side notes:
1) You don't need to send the intro over the socket; it's already on the client side.
2) Boolean variables like validCommand are conventionally 0 for false and 1 for true. You seem to have this flipped in your code. It's not wrong per se, just confusing to read.
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)
In debugging I can see that values of rx_buffer changes to what is send from client but printf function and even fputs function is not printng the value on terminal or updating the output file
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
// Constants defined
#define SERVER_PORT 3333
#define RX_BUFFER_SIZE 1024
#define TX_BUFFER_SIZE 1024
#define MAXCHAR 1000 // max characters to read from txt file
// Global variables
struct sockaddr_in dest_addr;
struct sockaddr_in source_addr;
char rx_buffer[RX_BUFFER_SIZE]; // buffer to store data from client
char tx_buffer[RX_BUFFER_SIZE]; // buffer to store data to be sent to client
char ipv4_addr_str[128]; // buffer to store IPv4 addresses as string
char ipv4_addr_str_client[128]; // buffer to store IPv4 addresses as string
int listen_sock;
char line_data[MAXCHAR];
FILE *input_fp, *output_fp;
int socket_create(struct sockaddr_in dest_addr, struct sockaddr_in source_addr){
int addr_family;
int ip_protocol;
dest_addr.sin_addr.s_addr = htonl(INADDR_ANY);
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(SERVER_PORT);
addr_family = AF_INET;
ip_protocol = IPPROTO_IP;
int sock,p;
printf("Create the socket\n");
sock=socket(addr_family , SOCK_STREAM , 0);
if((bind(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr)))<0){
perror("Bind failed.");
}
else{
printf("bind done");
}
char client[100];
listen(sock,1);
printf("Waiting for incoming connections...\n");
p = accept(sock, (struct sockaddr *)&source_addr, (socklen_t*)&source_addr);
if(p<0){ perror("accept failed");} printf("Client Address=%s\n",inet_ntop(AF_INET,&source_addr.sin_addr,client,sizeof(client)));
return p;
}
int receive_from_send_to_client(int sock){
char mess[10]="hello";
int len;
len=recv(sock , rx_buffer, sizeof(rx_buffer),0);
send(sock , mess , 5,0);
return 0;
}
int main() {
char *output_file_name = "data_from_client.txt";
// Create socket and accept connection from client
int sock = socket_create(dest_addr, source_addr);
output_fp = fopen(output_file_name, "w");
if (output_fp == NULL){
printf("Could not open file %s\n",output_file_name);
return 1;
}
while (1) {
receive_from_send_to_client(sock);
printf("%s",rx_buffer);
fputs(rx_buffer, output_fp);
fputs("\n", output_fp);
}
return 0;
}
In debugging I can see that values of rx_buffer are changing but not able to put that in file or print the message.
Note:- I am sending message from a python client.
in while ,you should open your file always and after putting data into the file close file descriptor properly.
see this code in main(),
int main() {
char *output_file_name = "data_from_client.txt";
// Create socket and accept connection from client
int sock = socket_create(dest_addr, source_addr);
while (1) {
output_fp = fopen(output_file_name, "a+");
if (output_fp == NULL){
printf("Could not open file %s\n",output_file_name);
return 1;
}
receive_from_send_to_client(sock);
printf("%s",rx_buffer);
fprintf(output_fp,"%s",rx_buffer);
fclose(output_fp);
}
return 0;
}
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.