I am trying to make a file transfer between server and client, but is working very badly. Basically what needs to happen is:
1) The client send a txt file to the server (I called it "quotidiani.txt")
2) The server saves it in another txt file ("receive.txt")
3) The server runs a script on it that modifies it and saves it with another name ("output.txt")
4) The server send the file back to the client that saves it (on the same socket) with the name (final.txt)
The problem is that the first file (quotidiani.txt) is read just for a little part, and then there are some errors. I'd like someone to help me understand and correct my errors.
Here's my code:
client.c:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <signal.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <netdb.h>
#define PORT 20000
#define LENGTH 512
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
/* Variable Definition */
int sockfd;
int nsockfd;
char revbuf[LENGTH];
struct sockaddr_in remote_addr;
/* Get the Socket file descriptor */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf(stderr, "ERROR: Failed to obtain Socket Descriptor! (errno = %d)\n",errno);
exit(1);
}
/* Fill the socket address struct */
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(PORT);
inet_pton(AF_INET, "127.0.0.1", &remote_addr.sin_addr);
bzero(&(remote_addr.sin_zero), 8);
/* Try to connect the remote */
if (connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1)
{
fprintf(stderr, "ERROR: Failed to connect to the host! (errno = %d)\n",errno);
exit(1);
}
else
printf("[Client] Connected to server at port %d...ok!\n", PORT);
/* Send File to Server */
//if(!fork())
//{
char* fs_name = "/home/aryan/Desktop/quotidiani.txt";
char sdbuf[LENGTH];
printf("[Client] Sending %s to the Server... ", fs_name);
FILE *fs = fopen(fs_name, "r");
if(fs == NULL)
{
printf("ERROR: File %s not found.\n", fs_name);
exit(1);
}
bzero(sdbuf, LENGTH);
int fs_block_sz;
while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs)) > 0)
{
if(send(sockfd, sdbuf, fs_block_sz, 0) < 0)
{
fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno);
break;
}
bzero(sdbuf, LENGTH);
}
printf("Ok File %s from Client was Sent!\n", fs_name);
//}
/* Receive File from Server */
printf("[Client] Receiveing file from Server and saving it as final.txt...");
char* fr_name = "/home/aryan/Desktop/progetto/final.txt";
FILE *fr = fopen(fr_name, "a");
if(fr == NULL)
printf("File %s Cannot be opened.\n", fr_name);
else
{
bzero(revbuf, LENGTH);
int fr_block_sz = 0;
while((fr_block_sz = recv(sockfd, revbuf, LENGTH, 0)) > 0)
{
int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);
if(write_sz < fr_block_sz)
{
error("File write failed.\n");
}
bzero(revbuf, LENGTH);
if (fr_block_sz == 0 || fr_block_sz != 512)
{
break;
}
}
if(fr_block_sz < 0)
{
if (errno == EAGAIN)
{
printf("recv() timed out.\n");
}
else
{
fprintf(stderr, "recv() failed due to errno = %d\n", errno);
}
}
printf("Ok received from server!\n");
fclose(fr);
}
close (sockfd);
printf("[Client] Connection lost.\n");
return (0);
}
server.c
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <signal.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <netdb.h>
#define PORT 20000
#define BACKLOG 5
#define LENGTH 512
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main ()
{
/* Defining Variables */
int sockfd;
int nsockfd;
int num;
int sin_size;
struct sockaddr_in addr_local; /* client addr */
struct sockaddr_in addr_remote; /* server addr */
char revbuf[LENGTH]; // Receiver buffer
/* Get the Socket file descriptor */
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
{
fprintf(stderr, "ERROR: Failed to obtain Socket Descriptor. (errno = %d)\n", errno);
exit(1);
}
else
printf("[Server] Obtaining socket descriptor successfully.\n");
/* Fill the client socket address struct */
addr_local.sin_family = AF_INET; // Protocol Family
addr_local.sin_port = htons(PORT); // Port number
addr_local.sin_addr.s_addr = INADDR_ANY; // AutoFill local address
bzero(&(addr_local.sin_zero), 8); // Flush the rest of struct
/* Bind a special Port */
if( bind(sockfd, (struct sockaddr*)&addr_local, sizeof(struct sockaddr)) == -1 )
{
fprintf(stderr, "ERROR: Failed to bind Port. (errno = %d)\n", errno);
exit(1);
}
else
printf("[Server] Binded tcp port %d in addr 127.0.0.1 sucessfully.\n",PORT);
/* Listen remote connect/calling */
if(listen(sockfd,BACKLOG) == -1)
{
fprintf(stderr, "ERROR: Failed to listen Port. (errno = %d)\n", errno);
exit(1);
}
else
printf ("[Server] Listening the port %d successfully.\n", PORT);
int success = 0;
while(success == 0)
{
sin_size = sizeof(struct sockaddr_in);
/* Wait a connection, and obtain a new socket file despriptor for single connection */
if ((nsockfd = accept(sockfd, (struct sockaddr *)&addr_remote, &sin_size)) == -1)
{
fprintf(stderr, "ERROR: Obtaining new Socket Despcritor. (errno = %d)\n", errno);
exit(1);
}
else
printf("[Server] Server has got connected from %s.\n", inet_ntoa(addr_remote.sin_addr));
/*Receive File from Client */
char* fr_name = "/home/aryan/Desktop/receive.txt";
FILE *fr = fopen(fr_name, "a");
if(fr == NULL)
printf("File %s Cannot be opened file on server.\n", fr_name);
else
{
bzero(revbuf, LENGTH);
int fr_block_sz = 0;
while((fr_block_sz = recv(nsockfd, revbuf, LENGTH, 0)) > 0)
{
int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);
if(write_sz < fr_block_sz)
{
error("File write failed on server.\n");
}
bzero(revbuf, LENGTH);
if (fr_block_sz == 0 || fr_block_sz != 512)
{
break;
}
}
if(fr_block_sz < 0)
{
if (errno == EAGAIN)
{
printf("recv() timed out.\n");
}
else
{
fprintf(stderr, "recv() failed due to errno = %d\n", errno);
exit(1);
}
}
printf("Ok received from client!\n");
fclose(fr);
}
/* Call the Script */
system("cd ; chmod +x script.sh ; ./script.sh");
/* Send File to Client */
//if(!fork())
//{
char* fs_name = "/home/aryan/Desktop/output.txt";
char sdbuf[LENGTH]; // Send buffer
printf("[Server] Sending %s to the Client...", fs_name);
FILE *fs = fopen(fs_name, "r");
if(fs == NULL)
{
fprintf(stderr, "ERROR: File %s not found on server. (errno = %d)\n", fs_name, errno);
exit(1);
}
bzero(sdbuf, LENGTH);
int fs_block_sz;
while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs))>0)
{
if(send(nsockfd, sdbuf, fs_block_sz, 0) < 0)
{
fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno);
exit(1);
}
bzero(sdbuf, LENGTH);
}
printf("Ok sent to client!\n");
success = 1;
close(nsockfd);
printf("[Server] Connection with Client closed. Server will wait now...\n");
while(waitpid(-1, NULL, WNOHANG) > 0);
//}
}
}
Some comments in no particular order:
You're passing up the opportunity to know exact errors too often:
if(listen(sockfd,BACKLOG) == -1)
{
printf("ERROR: Failed to listen Port %d.\n", PORT);
return (0);
}
This block should definitely include a perror("listen") or something similar. Always include perror() or strerror() in every error handling block when the error details will be reported via errno. Having exact failure reasons will save you hours when programming and will save you and your users hours when things don't work as expected in the future.
Your error handling needs some further standardizing:
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
{
printf("ERROR: Failed to obtain Socket Descriptor.\n");
return (0);
}
This should not return 0 because that will signal to the shell that the program ran to completion without error. You should return 1 (or use EXIT_SUCCESS and EXIT_FAILURE) to signal an abnormal exit.
else
printf("[Server] Server has got connected from %s.\n", inet_ntoa(addr_remote.sin_addr));
/*Receive File from Client */
In this preceding block you've gotten an error condition but continue executing anyway. That's a quick way to get very undesirable behavior. This should either re-start the main server loop or exit the child process or something similar. (Depends if you keep the multi-process server.)
if(!fork())
{
The preceding block forgot to account for fork() failing. fork() can, and does fail -- especially in shared hosting environments common at universities -- so you should be prepared for the full, complicated three possible return values from fork(): failure, child, parent.
It appears you're using fork() indiscriminately; your client and server are both very simple and the way they are designed to run means they cannot be used to service multiple clients simultaneously. You should probably stick to exactly one process for each, at least until the algorithm is perfectly debugged and you figure out some way to run multiple clients simultaneously. I expect this is the source of the problem you're encountering now.
You need to use functions to encapsulate details; write a function to connect to the server, a function to send the file, a function to write the file, etc. Write a function to handle the complicated partial writes. (I especially recommend stealing the writen function from the Advanced Programming in the Unix Environment book's source code. File lib/writen.c.) If you write the functions correctly you can re-use them in both the client and server. (Something like placing them in utils.c and compiling the programs like gcc -o server server.c utils.c.)
Having smaller functions that each do one thing will allow you to focus on smaller amounts of code at a time and write little tests for each that will help you narrow down which sections of code still need improvement.
One discussion point seems was missing here, So I thought to mention it here.
Let us very quicky understand TCP's data transfer. There are three steps
a)Connection Establishment, b)Data Transfer, c)Connection Termination
Now here a client is sending a file to a server, over a TCP socket.
The server does some processing on the file and sends it back to the client.
Now all the 3 steps need to done. Connection Establishment is done by calling connect.
Data reading/writing is done by recv/send here and connection termination is done by close.
The server here is reading data in a loop using recv.
Now when the loop will come to an end? When the recv returns 0 or may be less than 0 on error.
When recv returns 0? -> When the other side has closed the connection.
(When the TCP FIN segement has been recived by this side).
So in this code when the client has finished sending the file,I have used a shutdown function, which sends the FIN segement from the client side and the server's recv can now return 0 and the program continues.(Half way close, since the client also needs to read data subsequently).
(Just for understanding please note TCP's connection Establisment is a 3 way Handshake and
connection termination is a 4 way handshake.)
Similarly if you forget closing the connection socket on the server side, the client's recv will also block for ever.
I think that was the reason for using ctrl c to stop the client sometimes which you have mentioned.
You may pl. refer any standard Networking book or the rfc http://www.ietf.org/rfc/rfc793.txt for learning more about TCP
I have pasted the modified code and also little added some comments,
Hope this explanation will help.
Modified client code:
while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs)) > 0)
{
if(send(sockfd, sdbuf, fs_block_sz, 0) < 0)
{
fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno);
exit(1);
}
bzero(sdbuf, LENGTH);
}
/*Now we have sent the File's data, what about server's recv?
Recv is blocked and waiting for data to arrive or if the protocol
stack receives a TCP FIN segment ..then the recv will return 0 and
the server code can continue */
/*Sending the TCP FIN segment by shutdown and this is half way
close, since the client also needs to read data subsequently*/
shutdown(sockfd, SHUT_WR);
printf("Ok File %s from Client was Sent!\n", fs_name);
Related
I have to insert this code:
time_t ticks = time(NULL);
snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
to change the message displayed when someone connect to the server, from "Hello student!\n" to the current time and date, but I don't know where copy those two lines of code in the program and what I have to modify in the code after copying those two lines.
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
const char MESSAGE[] = "Hello student!\n";
int main(int argc, char *argv[]) {
int simpleSocket = 0;
int simplePort = 0;
int returnStatus = 0;
struct sockaddr_in simpleServer;
if (argc != 2) {
fprintf(stderr, "Usage: %s <port>\n", argv[0]);
exit(1);
}
simpleSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (simpleSocket == -1) {
fprintf(stderr, "Could not create a socket!\n");
exit(1);
}
else {
fprintf(stderr, "Socket created!\n");
}
/* retrieve the port number for listening */
simplePort = atoi(argv[1]);
/* setup the address structure */
/* use INADDR_ANY to bind to all local addresses */
memset(&simpleServer, '\0', sizeof(simpleServer));
simpleServer.sin_family = AF_INET;
simpleServer.sin_addr.s_addr = htonl(INADDR_ANY);
simpleServer.sin_port = htons(simplePort);
/* bind to the address and port with our socket */
returnStatus = bind(simpleSocket,(struct sockaddr *)&simpleServer,sizeof(simpleServer));
if (returnStatus == 0) {
fprintf(stderr, "Bind completed!\n");
}
else {
fprintf(stderr, "Could not bind to address!\n");
close(simpleSocket);
exit(1);
}
/* lets listen on the socket for connections */
returnStatus = listen(simpleSocket, 5);
if (returnStatus == -1) {
fprintf(stderr, "Cannot listen on socket!\n");
close(simpleSocket);
exit(1);
}
while (1)
{
struct sockaddr_in clientName = { 0 };
int simpleChildSocket = 0;
int clientNameLength = sizeof(clientName);
/* wait here */
simpleChildSocket = accept(simpleSocket,(struct sockaddr *)&clientName, &clientNameLength);
if (simpleChildSocket == -1) {
fprintf(stderr, "Cannot accept connections!\n");
close(simpleSocket);
exit(1);
}
/* handle the new connection request */
/* write out our message to the client */
write(simpleChildSocket, MESSAGE, strlen(MESSAGE));
close(simpleChildSocket);
}
close(simpleSocket);
return 0;
}
Thank you for your answers
A little introduction: about the original program
The program starts creating a socket and setting it to listen to a specific port, passed as an argument to your program with a command line such as programName <port>.
The port number is retrieved with the line simplePort = atoi(argv[1]);. There could have been a stricter check on the parameter (atoi() doesn't check if a number is actually provided), but I suppose it is ok for an entry level educational program.
After that, with the line
simpleChildSocket = accept(simpleSocket,(struct sockaddr *)&clientName, &clientNameLength);
the accept() function blocks until a connection request from a TCP client is received. As soon as the TCP handshake is completed (SYN / SYN-ACK / ACK, it is
called three-way handshake) a socket handle is returned (in your case simpleChildSocket) and that can be used to exchange data with the client.
The welcome message
After the accept is completed, and we are sure that all went fine, we soon come to our welcome message. With the lines
/* write out our message to the client */
write(simpleChildSocket, MESSAGE, strlen(MESSAGE));
the characters contained in the MESSAGE string (defined with the constant const char MESSAGE[] = "Hello student!\n";) are sent through write() function. Its parameters are
the socket descriptor
the pointer to the buffer to be sent
the number of bytes to be sent (in this case it corresponds to the length of MESSAGE, calculated with strlen(MESSAGE)
Note: write function can actually be used, but it is an unconventional choice. In fact it is a general function but when writing to sockets send() is actually used.
How to achieve you goal
All you have to do is to substitute MESSAGE in the write() call with the string containing the date:
{
char buff[30+1];
time_t ticks = time(NULL);
snprintf(buff, sizeof(buff), "%.30s\r\n", ctime(&ticks));
/* write out our message to the client */
write( simpleChildSocket, buff, strlen(buff) );
}
Don't forget to define your buff character buffer. I defined it locally but you can also allocate it dynamically.
The code provided by your teacher copies the time calculate with ctime() in the buff array (I increased its size in order to make sure that the whole datetime can be contained in it).
Then we call write as we previously did, just substituting MESSAGE and strlen(MESSAGE) with the new string buff and strlen(buff).
I have solved
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
/*const*/ char MESSAGE[100] = "";
char buff[100];
int main(int argc, char *argv[]) {
int simpleSocket = 0;
int simplePort = 0;
int returnStatus = 0;
struct sockaddr_in simpleServer;
if (argc != 2) {
fprintf(stderr, "Usage: %s <port>\n", argv[0]);
exit(1);
}
simpleSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (simpleSocket == -1) {
fprintf(stderr, "Could not create a socket!\n");
exit(1);
}
else {
fprintf(stderr, "Socket created!\n");
}
/* retrieve the port number for listening */
simplePort = atoi(argv[1]);
/* setup the address structure */
/* use INADDR_ANY to bind to all local addresses */
memset(&simpleServer, '\0', sizeof(simpleServer));
simpleServer.sin_family = AF_INET;
simpleServer.sin_addr.s_addr = htonl(INADDR_ANY);
simpleServer.sin_port = htons(simplePort);
/* bind to the address and port with our socket */
returnStatus = bind(simpleSocket,(struct sockaddr *)&simpleServer,sizeof(simpleServer));
if (returnStatus == 0) {
fprintf(stderr, "Bind completed!\n");
}
else {
fprintf(stderr, "Could not bind to address!\n");
close(simpleSocket);
exit(1);
}
/* lets listen on the socket for connections */
returnStatus = listen(simpleSocket, 5);
if (returnStatus == -1) {
fprintf(stderr, "Cannot listen on socket!\n");
close(simpleSocket);
exit(1);
}
while (1)
{
struct sockaddr_in clientName = { 0 };
int simpleChildSocket = 0;
int clientNameLength = sizeof(clientName);
/* wait here */
simpleChildSocket = accept(simpleSocket,(struct sockaddr *)&clientName, &clientNameLength);
if (simpleChildSocket == -1) {
fprintf(stderr, "Cannot accept connections!\n");
close(simpleSocket);
exit(1);
}
/* handle the new connection request */
/* write out our message to the client */
time_t ticks = time(NULL);
snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
strcpy(MESSAGE, buff);
write(simpleChildSocket, MESSAGE, strlen(MESSAGE));
close(simpleChildSocket);
}
close(simpleSocket);
return 0;
}
I have made simple server and client in c.Client waits for server until server is started.When i start the server data transmission between server and client is happening as per my expectation.When i close the server(not client) and again restarts the server,the first string from client to server is not transmitting.and then afterwards the client can send strings to server.So after restarting server client can't transmit first string to server.
Here is my client code(client.c),
/*header*/
#include<signal.h>
#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>
/*macros*/
/*size of the buffer*/
#define DATA_SIZE 200
/*function for thread*/
void *recieve_handler(void *);
/*stores the id of main thread*/
pthread_t main_id;
/*socket variable*/
int sockfd=0;
/*specifies the port number*/
#define PORT 5000
/*lenth of ip*/
#define LENGTH_OF_IP 100
int quit = 1;
void signal_handler(int n)
{
/*write null to server*/
write(sockfd,"",2);
/*close socket*/
close(sockfd);
printf("Exiting from applicationn");
exit(0);
}
int main(int argc, char *argv[])
{
/*buffer to send and receive*/
char received_data[DATA_SIZE],send_data[DATA_SIZE],server_ip[LENGTH_OF_IP],buf[DATA_SIZE]
,user_name[DATA_SIZE];
/*declare pointer for client config file*/
FILE* config_file;
/*flags*/
int clear = 1,server_port,usb_trap_on,n;
/*declaring socket object*/
struct sockaddr_in serv_addr;
/*thread declaration*/
pthread_t thread_id;
/*welcome messsage*/
printf("This is clientn");
printf("Enter somethingn");
printf("Server echos back the datan");
/*open client configuration file*/
if ((config_file = fopen("client.config","rw+")) == NULL)
{
printf("Could not open client config filen");
return 1;
}
/*parsing the file*/
while (fgets(buf, sizeof buf, config_file) != NULL) {
if (sscanf(buf,"IP=%s PORT=%d",server_ip,&server_port) == 2)
printf("%s %dn",server_ip,server_port);
if (fscanf(config_file,"usb_trap=%d",&usb_trap_on) == 1)
printf("usb flag is %dn",usb_trap_on);
}
/*create the socket*/
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
printf("n Error : Could not create socket n");
return 1;
}
/*By setsockopt kernal will release the socket
*if it is in use*/
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&clear,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
/*inialize all the variable of object serv_addr with 0*/
memset(&serv_addr, '0', sizeof(serv_addr));
/*AF_INET refers to addresses from the internet*/
serv_addr.sin_family = AF_INET;
/*specifies port address
*and The htons() function makes sure that numbers are stored
*in memory in network byte order, which is with the most
*significant byte first*/
serv_addr.sin_port = htons(server_port);
/* inet_pton - convert IPv4 and IPv6 addresses from text to binary form
* it returns 0 when coversion is unsucessful*/
if(inet_pton(AF_INET, server_ip, &serv_addr.sin_addr)<=0){
printf("n inet_pton error occuredn");
return 1;
}
/*connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))
*if connection is established then the memory for server will be
*allocated in client's memory
*and strting address of that memory is stored in scokfd
*i will return negative value if operation fails. */
while(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
printf("Wating for server to connectn");
sleep(1);
}
printf("Connection is donen");
printf("enter somethingn");
/*signal handling*/
signal(SIGTSTP,signal_handler);
/*create the thread to receive data*/
if( pthread_create( &thread_id , NULL , recieve_handler , (void*)&sockfd) < 0) {
perror("could not create thread");
return 1;
}
while(1) {
/*clear the buffer*/
memset(received_data,0,DATA_SIZE);
/*read from server*/
n = read(sockfd,received_data,sizeof(received_data));
/*if read error is occurred*/
if (n < 0) {
printf("Can't read received_datan");
break;
pthread_exit(&n);
}
if(n == 0) {
printf("Can't read received_datan");
break;
}
puts(received_data);
}
pthread_cancel(&thread_id);
/*close socket*/
if(!close(sockfd))
printf("Socket is closedn");
printf("Server is sutdown!!!!!!!!!!!!!n");
system("./client");
return 0;
}
void *recieve_handler(void *socket_desc)
{
/*received data buffer*/
char send_data[DATA_SIZE];
/*status flag*/
int n;
/*if pointer is empty*/
if(socket_desc == NULL) {
printf("socket_desc is NULLn");
n = 0;
pthread_exit(&n);
}
/*socket number*/
int sock = *(int*)socket_desc;
/*infinite loop*/
while (1){
/*clear buffer*/
memset(send_data, '0', sizeof(send_data));
/*get data from user*/
gets(send_data);
if((write(sock, send_data, strlen(send_data)+1)) == -1)
{
/*write data to server*/
printf("could not writen");
break;
}
}
}
here is my server code(server.c),
/*header*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
/*macros*/
/*maximum client that can be connected to server*/
#define MAX_CLIENT 10
/*size of the buffer*/
#define DATA_SIZE 200
/*specifies the port number*/
#define PORT 7000
int listenfd;
void signal_handler(int n)
{
printf("In handler\n");
char recived_data[DATA_SIZE];
write(listenfd,"\0",2);
read(listenfd, recived_data, sizeof(recived_data));/*write null to server*/
write(listenfd,"\0",2);
/*close socket*/
close(listenfd);
printf("Exiting from application\n");
exit(0);
}
int main(int argc, char *argv[])
{
/*signal handling*/
signal(SIGTSTP,signal_handler);
/*to store the recived data*/
char recived_data[DATA_SIZE];
/*sockaddr_in is a structure defined in netinet/in.h file.we are creating object of that
*strucure. */
struct sockaddr_in serv_addr;
/*flags*/
int connfd = 0 , clear = 1 ;
/*welcome message*/
printf("This simple server\n");
printf("It will echo data to client\n");
printf("If quit is recived from client then server will be existed\n");
/*Created socket*/
if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
printf("Can't create socket\n");
}
/*By setsockopt kernal will release the socket
*if it is in use*/
if (setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&clear,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
/*AF_INET refers to addresses from the internet*/
serv_addr.sin_family = AF_INET;
/*tells that any client can connect*/
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
/*specifies port address
*and The htons() function makes sure that numbers are stored
*in memory in network byte order, which is with the most
*significant byte first*/
serv_addr.sin_port = htons(PORT);
/*specifies port and adress of the socket*/
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
/*it will listen for connection
*MAX_CLIENT specifies the maximum client server can handle*/
listen(listenfd, MAX_CLIENT);
/*accept will assign the memory to client in server's memory area.here
*connfd has starting adress of assigned memory to client in server
*memory.*/
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
/*inet_ntoa(serv_addr.sin_addr) will return the adress of client*/
printf("[Server] Server has got connected from %s.\n", inet_ntoa(serv_addr.sin_addr));
printf("server waiting\n");
while(1){
/*read the data from memory and put in buffer*/
if(read(connfd, recived_data, sizeof(recived_data))){
/*if quit is recived then break the loop*/
if(!strcmp(recived_data,"quit"))
break;
/*put data on screen*/
puts(recived_data);
/*echo the data back to client*/
if(write(connfd,recived_data,strlen(recived_data)+1) == -1)
break;
}
else
{
printf("Could not read\n");
}
}
read(connfd, recived_data, sizeof(recived_data));
printf("server exiting\n");
/*close socket*/
close(connfd);
return(0);
}
here is client.config file(which is used be client to get ip,port of server)
IP=192.168.3.17 PORT=7000
usb_trap=0
This is my output of client when server is first time connected,
This is client
Enter something
Server echos back the data
192.168.3.17 7000
usb flag is 0
Wating for server to connect
Wating for server to connect
Connection is done
enter something
hello
hello
i am jay
i am jay
Above output is as per my expectation.
Now below is my output of client when server is reconnected(server is disconnected ,and then started again)
Socket is closed
Server is sutdown!!!!!!!!!!!!!
This is client
Enter something
Server echos back the data
192.168.3.17 7000
usb flag is 0
Wating for server to connect
Wating for server to connect
Wating for server to connect
Wating for server to connect
Connection is done
enter something
hello
could not write
jay
jay
So in above output client can't write first string to server.
Client signal handler:
void signal_handler(int n)
{
/*write null to server*/
write(sockfd,"",2);
/*close socket*/
close(sockfd);
printf("Exiting from applicationn");
exit(0);
}
Everything wrong here that could be wrong. No error checking. You can't do I/O in signal handlers. You can't block in signal handlers. You don't need to 'write null to server'. Exiting the application will close the socket, or reset it.
Client:
while(1) {
/*clear the buffer*/
memset(received_data,0,DATA_SIZE);
Unnecessary. Remove.
if (n < 0) {
printf("Can't read received_datan");
A pointless message. You got an error. Print the error, with perror(), or by incorporating strerror() into the message.
if(n == 0) {
printf("Can't read received_datan");
An incorrect message. This situation is not the same as the previous one. You got end of stream. The peer has disconnected. Say so.
puts(received_data);
Wrong. The data received is only valid up to n bytes. The correct way to print it is via printf("%.*s", n, received_data);
Client 'receive handler':
void *recieve_handler(void *socket_desc)
Apart from the mis-spelling, why is this called a receive handler when it doesn't receive? and does send?
memset(send_data, '0', sizeof(send_data));
/*get data from user*/
gets(send_data);
You probably meant '\0' here, as there are numerous other backslashes missing from your code, but the memset() is completely unnecessary. Remove.
Server signal handler:
void signal_handler(int n)
{
printf("In handler\n");
char recived_data[DATA_SIZE];
write(listenfd,"\0",2);
read(listenfd, recived_data, sizeof(recived_data));/*write null to server*/
write(listenfd,"\0",2);
/*close socket*/
close(listenfd);
printf("Exiting from application\n");
exit(0);
}
This is all nonsense from start to finish. You can't do I/O in a signal handler; you can't do I/O with a listening socket; you can't block in a signal handler; and you don't need to do any of it. The operating system will either close or reset the socket. Either way the peer will find out via the return value of read() or recv().
Server loop:
if(read(connfd, recived_data, sizeof(recived_data))){
Incorrect. It is never correct to call read() or recv() without storing the return value into a variable. You have to test it for -1, test it for zero, and otherwise use it as the length of data received. You can't accomplish that without a variable. See your own client code for an example, after my corrections.
if(!strcmp(recived_data,"quit"))
Invalid. There is no guarantee that you will receive a null-terminated string. And you haven't checked for EOS or an error first.
puts(recived_data);
Invalid for the same reason as the puts() in the client as discussed above.
if(write(connfd,recived_data,strlen(recived_data)+1) == -1)
Invalid. The length of the data received is given by the return value of read() if positive, not by strlen(). See discussion above.
else
{
printf("Could not read\n");
}
See discussion above about indiscriminate error messages like this. No use at all.
read(connfd, recived_data, sizeof(recived_data));
What is this? Remove.
Problem is that you are not canceling the thread properly.
Use
pthread_cancel(thread_id);
instead of
pthread_cancel(&thread_id);
So now thread will be canceled.and that thread will not be lived.
i am developing a client server program using socket in c which is my unfamiliar programming language, my program will run on linux environment. I had recheck my establishment connection's program for both side which didnt have any error and all the required thing also being declare in a nice manner but when i run my server program, it show me waiting for client.Unfortunately, when i execute the client program, it only show me usage: %s <filename> <IP address> [port number], the %s is use to display the file. There consist of one solution which i can think out but i also not sure it's the correct solution or not,i plan to use exec() system call to insert my exe file and file into it, because the exec() can use for execute a executable file directly. What do i planning is correct or not ? Here is my client program
*i use gcc to get an exe file first ,after that i issue ./exeFile to compile my exe file
/* getfile client */
#include <stdio.h> /* printf and standard I/O */
#include <sys/socket.h> /* socket, connect, socklen_t */
#include <arpa/inet.h> /* sockaddr_in, inet_pton */
#include <string.h> /* strlen */
#include <stdlib.h> /* atoi */
#include <fcntl.h> /* O_WRONLY, O_CREAT */
#include <unistd.h> /* close, write, read */
#define SRV_PORT 5105
#define MAX_RECV_BUF 256
#define MAX_SEND_BUF 256
int recv_file(int ,char*);
int main(int argc, char* argv[])
{
int sock_fd;
struct sockaddr_in srv_addr;
if (argc < 3)
{
printf("usage: %s <filename> <IP address> [port number]\n", argv[0]);
exit(EXIT_FAILURE);
}
memset(&srv_addr, 0, sizeof(srv_addr)); /* zero-fill srv_addr structure*/
/* create a client socket */
sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
srv_addr.sin_family = AF_INET; /* internet address family */
/* convert command line argument to numeric IP */
if ( inet_pton(AF_INET, argv[2], &(srv_addr.sin_addr)) < 1 )
{ printf("Invalid IP address\n");
exit(EXIT_FAILURE);
}
/* if port number supplied, use it, otherwise use SRV_PORT */
srv_addr.sin_port = (argc > 3) ? htons(atoi(argv[3])) : htons(SRV_PORT);
if( connect(sock_fd, (struct sockaddr*) &srv_addr, sizeof(srv_addr)) < 0 )
{
perror("connect error");
exit(EXIT_FAILURE);
}
printf("connected to:%s:%d ..\n",argv[2],SRV_PORT);
recv_file(sock_fd, argv[1]); /* argv[1] = file name */
/* close socket*/
if(close(sock_fd) < 0)
{
perror("socket close error");
exit(EXIT_FAILURE);
}
return 0;
}
int recv_file(int sock, char* file_name)
{
char send_str [MAX_SEND_BUF]; /* message to be sent to server*/
int f; /* file handle for receiving file*/
ssize_t sent_bytes, rcvd_bytes;
int recv_count,rcvd_file_size; /* count of recv() calls*/
char recv_str[MAX_RECV_BUF]; /* buffer to hold received data */
size_t send_strlen; /* length of transmitted string */
sprintf(send_str, "%s\n", file_name); /* add CR/LF (new line) */
send_strlen = strlen(send_str); /* length of message to be transmitted */
if( (sent_bytes = send(sock, file_name, send_strlen, 0)) < 0 )
{
perror("send error");
return -1;
}
/* attempt to create file to save received data. 0644 = rw-r--r-- */
if ( (f = open(file_name, O_WRONLY|O_CREAT, 0644)) < 0 )
{
perror("error creating file");
return -1;
}
recv_count = 0; /* number of recv() calls required to receive the file */
rcvd_file_size = 0; /* size of received file */ /* continue receiving until ? (data or close) */
while ( (rcvd_bytes = recv(sock, recv_str, MAX_RECV_BUF, 0)) > 0 )
{
recv_count++;
rcvd_file_size += rcvd_bytes;
if (write(f, recv_str, rcvd_bytes) < 0 )
{
perror("error writing to file");
return -1;
}
}
close(f); /* close file*/
printf("Client Received: %d bytes in %d recv(s)\n", rcvd_file_size, recv_count);
return rcvd_file_size;
}
i can provide my server program if needed
In order to slake my thirst for C knowledge, on two linux boxes connected to my home network, I'm writing kind of a skeleton telnet that send()s and recv()s strings (just for some experience with sockets and threads). The server listens and the client connects and sends strings from stdin. I got those to work then I changed them to implement pthreads and the threaded versions worked. Last, I put the two together into one program so that either end of the connection could (in theory) send and receive strings. Both the client and server use strstr() to watch for "quit" and then quit. As the title of this post implies, when I put it all together, the combined version will send strings but it doesn't quit when it is supposed to. I'm not sure what went wrong. I tried to step through it with gdb but I'm just too inexperienced with gdb and couldn't tell what is happening.
So, why won't it quit?
To kind of take a step back, is there a better way to implement what I'm trying to do?
Thanks for any help.
clientserver.c
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
int sockfd = 0, send_running = 1, recv_running = 1, status = 0, acptsockfd = 0;
char str_to_send[200], str_rcvd[200];
char *remote_host_addr_str = NULL;
struct sockaddr_in remote_addr, listening_addr;
void *sender(void *threadid);
void *receiver(void *threadid);
int main(int argc, char *argv[])
{
pthread_t threads[2];
long t = 0;
memset(&remote_addr, 0, sizeof remote_addr);
memset(&listening_addr, 0, sizeof listening_addr);
str_to_send[0] = '\0';
str_rcvd[0] = '\0';
if(argc != 2)
{
fprintf(stderr, "\n Usage: %s <IP of host to connect to> \n", argv[0]);
return 1;
}
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
fprintf(stderr, "\n Socket Error %s\n", strerror(errno));
return 1;
}
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(1234);
remote_host_addr_str = argv[1];
if(inet_pton(AF_INET, argv[1], &remote_addr.sin_addr)<=0)
{
fprintf(stderr, "\n inet_pton error \n");
return 1;
}
listening_addr.sin_addr.s_addr = htonl(INADDR_ANY);
listening_addr.sin_port = htons(1234);
status = pthread_create(&threads[t], NULL, receiver, (void *)t);
if(status)
{
fprintf(stderr, "Error: pthread_create(receiver) returned %d\n", status);
exit(-1);
}
status = pthread_create(&threads[t+1], NULL, sender, (void *)t);
if(status)
{
fprintf(stderr, "Error: pthread_create(sender) returned %d\n", status);
exit(-1);
}
while(send_running && recv_running)
continue;
pthread_exit(NULL);
return 0;
}
void *sender(void *threadid)
{
if (connect(sockfd, (struct sockaddr *)&remote_addr, sizeof remote_addr) == -1)
{
fprintf(stderr, "socket error %s", strerror(errno));
send_running = 0;
}
while(1)
{
fgets(str_to_send, sizeof str_to_send, stdin);
send(sockfd, str_to_send, sizeof str_to_send, 0);
if((strstr(str_to_send, "quit")) || strstr(str_rcvd, "quit"))
{
send_running = 0;
recv_running = 0;
pthread_exit(NULL);
break;
}
}
send_running = 0;
}
void *receiver(void *threadid)
{
bind(sockfd, (struct sockaddr*)&listening_addr, sizeof listening_addr);
listen(sockfd, 5);
acptsockfd = accept(sockfd, (struct sockaddr *)NULL, NULL);
while(1)
{
recv(acptsockfd, str_rcvd, sizeof str_rcvd, 0);
if(str_rcvd[0] != '\0')
printf("%s", str_rcvd);
if(strstr(str_rcvd, "quit"))
{
close(acptsockfd);
recv_running = 0;
send_running = 0;
pthread_exit(NULL);
break;
}
}
recv_running = 0;
}
From the pthread_exit synopsis
An implicit call to pthread_exit() is made when a thread other than
the thread in which main() was first invoked returns from the start
routine that was used to create it. The function's return value serves
as the thread's exit status.
You are calling pthread_exit() unnecessarily. If you're able to return from your function normally, then the thread will finish correctly. I would prefer to just return from the function if you can.
I think you'll find that the send_running and recv_running flags are superfluous. Basically, if both the send and receive functions loop until they reach their exit condition ("quit" was sent or received), then they return, then the main function should be able to wait on the other two threads. Look at pthread_join. This will eliminate the busy-waiting (looping on send_running && recv_running) in your main function.
As to why the process doesn't end? I don't think the receiver function is ever exiting, so the process won't end until all threads are finished. The receiver function is only checking to see if "quit" was received. If you send "quit", the sender function will quit normally, as will main, but receiver will continually wait to receive the value "quit".
You shouldn't use the same socket to do listen and connect. Use two sockets.
This is the fixed code for what I was trying to do.
/*
* clientserver.c -- send and receive strings over a socket using threads
*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
const long MYSENDER = 0; // send thread ID
const long MYRECVR = 1; // recv thread ID
int sockfd = 0, out_sockfd = 0, status = 0, acptsockfd = 0, fdmax = 0; // socket file descriptors, exit status, largest file descriptor
char str_to_send[200], str_rcvd[200]; // send and receive buffers
char *remote_host_addr_str = NULL; // IP address of host to connect to from command line argument
struct sockaddr_in remote_addr, listening_addr; // remote host and listening socket params
fd_set master_fdset; // file descriptor set for select()
unsigned char flags = 0; // operating conditions
const unsigned char ACCEPTED_CONNECTION = 1; // the receive function has accepted a connection
const unsigned char SEND_RUNNING = 1<<1; // the send function is running
const unsigned char RECV_RUNNING = 1<<2; // the receive function is running
pthread_mutex_t flag_mutex; // so all threads can safely read & write the flags variable
void *sender(void *threadid);
void *receiver(void *threadid);
int main(int argc, char *argv[])
{
FD_ZERO(&master_fdset); // initialize file descriptor set
pthread_t threads[2]; // two threads: send and receive
pthread_mutex_init(&flag_mutex, NULL); // initialize flags mutex
memset(&remote_addr, 0, sizeof remote_addr); // initialize to zero
memset(&listening_addr, 0, sizeof listening_addr); // initialize to zero
str_to_send[0] = '\0'; // initialize to NULL char
str_rcvd[0] = '\0'; // initialize to NULL char
if(argc != 2) // expecting an IP address
{
fprintf(stderr, "\n Usage: %s <IP of host to connect to> \n", argv[0]);
return 1;
}
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) // create listening socket and check for error
{
fprintf(stderr, "\n socket() error %s\n", strerror(errno));
return 1;
}
if((out_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) // create sending socket and check for error
{
fprintf(stderr, "\n socket() Error %s\n", strerror(errno));
return 1;
}
/* fill in details about remote host socket */
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(1234);
remote_host_addr_str = argv[1];
if(inet_pton(AF_INET, argv[1], &remote_addr.sin_addr)<=0)
{
fprintf(stderr, "\n inet_pton error \n");
return 1;
}
/* fill in details about listening socket */
listening_addr.sin_addr.s_addr = htonl(INADDR_ANY);
listening_addr.sin_port = htons(1234);
status = pthread_create(&threads[MYRECVR], NULL, receiver, (void *)MYRECVR); // start the server thread and check for error
if(status)
{
fprintf(stderr, "Error: pthread_create(receiver) returned %d\n", status);
exit(-1);
}
pthread_mutex_lock(&flag_mutex);
flags |= RECV_RUNNING; // server thread is running
pthread_mutex_unlock(&flag_mutex);
sleep(1); // wait to see if an incoming connection was accepted
pthread_mutex_lock(&flag_mutex);
if(flags & ACCEPTED_CONNECTION) //received an incoming connection
out_sockfd = acptsockfd;
pthread_mutex_unlock(&flag_mutex);
status = pthread_create(&threads[MYSENDER], NULL, sender, (void *)MYSENDER); // start the client thread and check for error
if(status)
{
fprintf(stderr, "Error: pthread_create(sender) returned %d\n", status);
exit(-1);
}
pthread_mutex_lock(&flag_mutex);
flags |= SEND_RUNNING; // client thread is running
pthread_mutex_unlock(&flag_mutex);
pthread_join(threads[MYRECVR], NULL); // main() will wait for the server thread to complete
pthread_join(threads[MYSENDER], NULL); // main() will wait for the client thread to complete
return 0;
}
void *sender(void *threadid)
{
int c; // loop counter
fprintf(stderr, "Connecting to %s\n", remote_host_addr_str);
for(c = 0; c < 12; ++c)
{
if (connect(out_sockfd, (struct sockaddr *)&remote_addr, sizeof remote_addr) == -1) // connect to the remote host. Retry every 5 sec for 1 min
{
fprintf(stderr, "Send socket error: %s\nRetrying in 5 seconds. %d tries remaining.\n", strerror(errno), (11 - c));
int d;
/* show the user a countdown to next retry on the screen */
fprintf(stderr, " ");
for(d=5; d>0; --d)
{
fprintf(stderr, "\b%d", d);
sleep(1);
}
fprintf(stderr, "\b \b");
if(c < 11)
continue;
else // failed to connect to remote host. Shutdown client thread
{
pthread_mutex_lock(&flag_mutex);
flags &= !SEND_RUNNING;
pthread_mutex_unlock(&flag_mutex);
return (int*)1;
}
}
else
{
fprintf(stderr, "Connected!\n");
c += 12;
}
}
while(1)
{
if(fgets(str_to_send, sizeof str_to_send, stdin) == NULL) // get input from stdin. Shutdown client thread on error
goto shutdown_send_function;
if((status = send(out_sockfd, str_to_send, strlen(str_to_send)+2, 0)) == -1) // send the input from stdin and check for error
fprintf(stderr, "send() error : %s\n", strerror(errno));
pthread_mutex_lock(&flag_mutex);
status = (flags & RECV_RUNNING); // make sure the server thread is still running
pthread_mutex_unlock(&flag_mutex);
if((strstr(str_to_send, "quit")) || !status) // shutdown if the message contains "quit" or the server thread stopped
{
shutdown_send_function:
pthread_mutex_lock(&flag_mutex);
flags &= !SEND_RUNNING;
pthread_mutex_unlock(&flag_mutex);
if(out_sockfd != acptsockfd) // if the sending socket is different than the accepted socket
if((status = close(sockfd)) == -1) // close the sending socket
fprintf(stderr, "close() error : %s\n", strerror(errno));
break;
}
}
return 0;
}
void *receiver(void *threadid)
{
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if(bind(sockfd, (struct sockaddr*)&listening_addr, sizeof listening_addr) == -1) // bind the listening socket and check for error
fprintf(stderr, "bind() error : %s\n", strerror(errno));
fprintf(stderr, "Waiting for incoming connection\n");
if(listen(sockfd, 5) == -1) // listen for incoming connections
fprintf(stderr, "listen() error : %s\n", strerror(errno));
FD_SET(sockfd, &master_fdset); // add the listening socket to the file descriptor set
fdmax = sockfd; // keep track of the largest file descriptor for select()
if((acptsockfd = accept(sockfd, (struct sockaddr *)NULL, NULL)) == -1) // accept incoming connection request and check for error
fprintf(stderr, "accept() error : %s\n", strerror(errno));
FD_SET(acptsockfd, &master_fdset); // add accepted socket to file descriptor set
if(acptsockfd > fdmax) // keep track of the largest file descriptor for select()
fdmax = acptsockfd;
pthread_mutex_lock(&flag_mutex);
flags |= ACCEPTED_CONNECTION; // a connection has been accepted
pthread_mutex_unlock(&flag_mutex);
fprintf(stderr, "Incoming connection detected\n");
while(1)
{
if((status = select(fdmax+1, &master_fdset, 0, 0, NULL)) > 0) // there is data available to be read
{
if(recv(acptsockfd, str_rcvd, sizeof str_rcvd, 0) == -1) // receive the data and check for error
fprintf(stderr, "recv() error : %s\n", strerror(errno));
if(str_rcvd[0] != '\0')
printf("%s", str_rcvd); // print the message received
pthread_mutex_lock(&flag_mutex);
status = (flags & SEND_RUNNING); // check if the client thread is still running
pthread_mutex_unlock(&flag_mutex);
if((strstr(str_rcvd, "quit")) || !status) // shutdown the server thread if message contains "quit" or client thread stopped
{
if((status = close(acptsockfd)) == -1) // close the accepted socket
fprintf(stderr, "close() error : %s\n", strerror(errno));
pthread_mutex_lock(&flag_mutex);
flags &= !RECV_RUNNING;
pthread_mutex_unlock(&flag_mutex);
break;
}
}
if(status == -1)
fprintf(stderr, "select() error : %s\n", strerror(errno));
}
return 0;
}
I'm trying TCP file transfer on Linux. After establishing the connection, the server should send "send.txt" to the client, and the client receives the file and saves it as "receive.txt". Then the connection breaks.
The correct input and output should be:
Server terminal:
$./server &
[server] obtain socket descriptor successfully.
[server] bind tcp port 5000 in addr 0.0.0.0 successfully.
[server] listening the port 5000 successfully.
[server] server has got connect from 127.0.0.1.
[server] send send.txt to the client…ok!
[server] connection closed.
Client terminal:
$./client
[client] connected to server at port 5000…ok!
[client] receive file sent by server to receive.txt…ok!
[client] connection lost.
And both the server and client should exit after the process.
But what I've got now gives
$ ./server &
[server] obtain socket descriptor successfully.
[server] bind tcp port 5000 in addr 0.0.0.0 sucessfully.
[server] listening the port 5000 sucessfully.
[server] server has got connect from 127.0.0.1.
[server] send send.txt to the client...ok!
[server] connection closed.
/*Here the server doesn't exit*/
$ ./client
[client] connected to server at port 5000...ok!
/*Here the client doesn't exit*/
Also, an EMPTY "receive.txt" is generated.
My code was first written for transferring simple strings, and it worked correctly. So I guess the problem lies in the file transferring part.
My code is as follows:
server.c
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#define PORT 5000 // The port which is communicate with server
#define BACKLOG 10
#define LENGTH 512 // Buffer length
int main ()
{
int sockfd; // Socket file descriptor
int nsockfd; // New Socket file descriptor
int num;
int sin_size; // to store struct size
struct sockaddr_in addr_local;
struct sockaddr_in addr_remote;
/* Get the Socket file descriptor */
if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
{
printf ("ERROR: Failed to obtain Socket Descriptor.\n");
return (0);
}
else printf ("[server] obtain socket descriptor successfully.\n");
/* Fill the local socket address struct */
addr_local.sin_family = AF_INET; // Protocol Family
addr_local.sin_port = htons(PORT); // Port number
addr_local.sin_addr.s_addr = INADDR_ANY; // AutoFill local address
bzero(&(addr_local.sin_zero), 8); // Flush the rest of struct
/* Bind a special Port */
if( bind(sockfd, (struct sockaddr*)&addr_local, sizeof(struct sockaddr)) == -1 )
{
printf ("ERROR: Failed to bind Port %d.\n",PORT);
return (0);
}
else printf("[server] bind tcp port %d in addr 0.0.0.0 sucessfully.\n",PORT);
/* Listen remote connect/calling */
if(listen(sockfd,BACKLOG) == -1)
{
printf ("ERROR: Failed to listen Port %d.\n", PORT);
return (0);
}
else printf ("[server] listening the port %d sucessfully.\n", PORT);
int success = 0;
while(success == 0)
{
sin_size = sizeof(struct sockaddr_in);
/* Wait a connection, and obtain a new socket file despriptor for single connection */
if ((nsockfd = accept(sockfd, (struct sockaddr *)&addr_remote, &sin_size)) == -1)
printf ("ERROR: Obtain new Socket Despcritor error.\n");
else printf ("[server] server has got connect from %s.\n", inet_ntoa(addr_remote.sin_addr));
/* Child process */
if(!fork())
{
char* f_name = "send.txt";
char sdbuf[LENGTH]; // Send buffer
printf("[server] send %s to the client...", f_name);
FILE *fp = fopen(f_name, "r");
if(fp == NULL)
{
printf("ERROR: File %s not found.\n", f_name);
exit(1);
}
bzero(sdbuf, LENGTH);
int f_block_sz;
while((f_block_sz = fread(sdbuf, sizeof(char), LENGTH, fp))>0)
{
if(send(nsockfd, sdbuf, f_block_sz, 0) < 0)
{
printf("ERROR: Failed to send file %s.\n", f_name);
break;
}
bzero(sdbuf, LENGTH);
}
printf("ok!\n");
success = 1;
close(nsockfd);
printf("[server] connection closed.\n");
while(waitpid(-1, NULL, WNOHANG) > 0);
}
}
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define PORT 5000
#define LENGTH 512 // Buffer length
int main(int argc, char *argv[])
{
int sockfd; // Socket file descriptor
char revbuf[LENGTH]; // Receiver buffer
struct sockaddr_in remote_addr;
/* Get the Socket file descriptor */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
printf("ERROR: Failed to obtain Socket Descriptor!\n");
return (0);
}
/* Fill the socket address struct */
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(PORT);
inet_pton(AF_INET, "127.0.0.1", &remote_addr.sin_addr);
bzero(&(remote_addr.sin_zero), 8);
/* Try to connect the remote */
if (connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1)
{
printf ("ERROR: Failed to connect to the host!\n");
return (0);
}
else printf("[client] connected to server at port %d...ok!\n", PORT);
//printf ("OK: Have connected to %s\n",argv[1]);
printf("[client] receive file sent by server to receive.txt...");
char* f_name = "receive.txt";
FILE *fp = fopen(f_name, "a");
if(fp == NULL) printf("File %s cannot be opened.\n", f_name);
else
{
bzero(revbuf, LENGTH);
int f_block_sz = 0;
int success = 0;
while(success == 0)
{
while(f_block_sz = recv(sockfd, revbuf, LENGTH, 0))
{
if(f_block_sz < 0)
{
printf("Receive file error.\n");
break;
}
int write_sz = fwrite(revbuf, sizeof(char), f_block_sz, fp);
if(write_sz < f_block_sz)
{
printf("File write failed.\n");
break;
}
bzero(revbuf, LENGTH);
}
printf("ok!\n");
success = 1;
fclose(fp);
}
}
close (sockfd);
printf("[client] connection lost.\n");
return (0);
}
Thank you very much!
You need to add code to the f_block_sz code. recv() has a few posible return values:
<0 -- Error, error number in errno (errno.h)
0 -- Connection closed
>0 -- Data read, number of bytes
You need to handle the second case. Add this else case:
else if(f_block_sz)
{
break;
}
So that the loop will be broken when the server closes the connection, and your code will print you [client] connection lost and exit.
You have another problem in that your server program is multiprocess and forks every time it gets an incoming connection. The parent stays alive to accept new connections and the child processes the connection. The exit from the child process is not enough to cause the parent to exit as well.
If you only want to process one connection then don't use fork.
If you wish to continue your current setup then you will need to change the child process to use _exit instead of exit and get the parent process to handle the SIGCHLD signal (received when a child process exits).
ie.
#include <signal.h>
void terminate(int signal) {
// close sockfd -- you will need to make it global
// or have terminate alter some global variable that main can monitor to
// detect when it is meant to exit
exit(0); // don't exit if you choose the second option
}
int main() {
signal(SIGCHLD, terminate);
...
}