i'm making a small client-server application,where server forks a child process after accept,for multiple connections while the client connects to it ,sends a message and receives a response. following is my code fragment:
-- client.c
char buffer[256];
portno=5001;
/* Create a socket point */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("ERROR opening socket");
exit(1);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portno);
/* Now connect to the server */
if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR connecting");
exit(1);
}
/* Now ask for a message from the user, this message
* will be read by server
*/
while(1)
{
printf("Please enter the message: ");
bzero(buffer,256);
fgets(buffer,255,stdin);
/* Send message to the server */
n = write(sockfd, buffer, strlen(buffer));
if (n < 0) {
perror("ERROR writing to socket");
exit(1);
}
/* Now read server response */
bzero(buffer,256);
n = read(sockfd, buffer, 255);
if(n==0)
{
perror("nothing to read");
}
if (n < 0) {
perror("ERROR reading from socket");
exit(1);
}
printf("%s\n",buffer);
}
--server.c
int main( int argc, char *argv[] ) {
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n, pid;
/* First call to socket() function */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("ERROR opening socket");
exit(1);
}
/* Initialize socket structure */
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = 5001;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
/* Now bind the host address using bind() call.*/
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR on binding");
exit(1);
}
/* Now start listening for the clients, here
* process will go in sleep mode and will wait
* for the incoming connection
*/
listen(sockfd,5);
clilen = sizeof(cli_addr);
while (1) {
newsockfd = accept(sockfd, (struct sockaddr *)NULL,NULL);
if (newsockfd < 0) {
perror("ERROR on accept");
exit(1);
}
/* Create child process */
pid = fork();
if (pid < 0) {
perror("ERROR on fork");
exit(1);
}
if (pid == 0)
{
while(1)
{
/* This is the client process */
close(sockfd);
doprocessing(newsockfd);
/** exit(0); **/
}
}
else {
close(newsockfd);
}
} /* end of while */
}
void doprocessing (int sock) {
int n;
char buffer[256];
bzero(buffer,256);
n = read(sock,buffer,255);
if(n==0)
{
perror("nothing to read");
}
if (n < 0) {
perror("ERROR reading from socket");
exit(1);
}
printf("Here is the message: %s\n",buffer);
n = write(sock,"I got your message",18);
if (n <= 0) {
perror("ERROR writing to socket");
exit(1);
}
}
when i run the both,O/P is following:
Please enter the message: arjun
I got your message
Please enter the message: gaur
ERROR reading from socket: Connection reset by peer
Please help.how to resolve this
The forked child process is exiting without closing newsockfd. On some platforms that causes a connection reset instead of an orderly close.
You also need to check the result of recv() for zero and handle it correctly, i.e. not as an error, and you also need to use a positive return value correctly, e.g. instead of
printf("%s\n",buffer);
it should be
printf("%.*s\n",n,buffer);
What happens is:
Server starts listening.
Client connects to listening server.
Server forks of process serving client.
Client sends data.
Serving process as of 3. receives date from client and prints it.
Serving process as of 3. sends response to client.
Serving process as of 3. exists/ends and with this its accepted socket (the peer to the client) gets closed.
Client receives response and prints it.
Client tries to send more data to the serving process as of 3..
Client tries to read more data from the serving process as of 3..
Step 10. fails because the serving process as of 3. already ended (step 7.)
Your client does this:
Connect to the server
Send some data to the server
Receive some data from the server
Send some data to the server
Receive some data from the server
...
but your server does this (possibly with multiple connections at once):
Wait for a connection
Receive some stuff from the client
Send some stuff to the client
Close the connection (by exiting the only process that has the connection open)
So the server closes the connection when the client is about to send some more data, and the client gets an error because the server closed the connection.
You need to either make the server keep receiving and sending data in a loop (so it can happen several times on the same connection), or make the client make a new connection each time it wants to send something.
Related
I am checking the communication between 2 entities (A and B) for their presence. A is a server and B is a client. When the server is up and running, it waits for connections and when B starts, it sends a message "Available" every one second. Now, the problem is, when I terminate the B program( ctrl+c or press the close button of the terminal), the server A does not recognise and still continues its operation. I would like for it to display message like "B is no more available" or "communicating partner is off". I understand TCP would be a best fit for the connection oriented communication. Please suggest me the changes to incorporate the display message on server A, when B is closed.
PS: amateur in socket programming
EDIT1: Managed to display the Message. However, since the server is designed to listen to many connections, I would like to make it accept the connections and not end the loop. Any guidance here would be useful.
SERVER(A) TCP SERVER
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
int main( int argc, char *argv[] ) {
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
/* Initialize socket structure */
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = 5001;
// create socket and get file descriptor
sockfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
clilen = sizeof(cli_addr);
// bind the host address using bind() call
if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
perror("ERROR on binding\n");
exit(1);
}
// start listening for the clients,
// here process will go in sleep mode and will wait for the incoming connection
listen(sockfd, 5);
// accept actual connection from the client
newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
// inside this while loop, implemented communication with read/write or send/recv function
//printf("start");
while (1) {
bzero(buffer,256);
n = read(newsockfd, buffer, 255);
if (n < 0){
perror("ERROR in reading from socket");
exit(1);
}
if (n == 0){
perror("Client has abruptly ended\n");
close(sockfd);
exit(1);
}
printf("client said: %s \n", buffer);
n = write(newsockfd, buffer, strlen(buffer));
if (n < 0){
perror("ERROR in writing to socket");
exit(1);
}
// escape this loop, if the client sends message "quit"
// if (!bcmp(buffer, "quit", 4))
// break;
}
return 0;
}
CLIENT(B) TCP CLIENT
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
int main(int argc, char *argv[]) {
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
portno = 5001;
// create socket and get file descriptor
sockfd = socket(AF_INET, SOCK_STREAM, 0);
server = gethostbyname("127.0.0.1");
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(portno);
// connect to server with server address which is set above (serv_addr)
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR while connecting");
exit(1);
}
// inside this while loop, implement communicating with read/write or send/recv function
while (1) {
strcpy(buffer,"Available");
n = write(sockfd,buffer,strlen(buffer));
if (n < 0){
perror("ERROR while writing to socket");
exit(1);
}
bzero(buffer,256);
n = read(sockfd, buffer, 255);
if (n < 0){
perror("ERROR while reading from socket");
exit(1);
}
printf("server replied: %s \n", buffer);
// escape this loop, if the server sends message "quit"
//if (!bcmp(buffer, "quit", 4))
// break;
sleep(1);
}
return 0;
}
Please anybody tell me how to handle that issue?
When the client closes the TCP connection, the server's call to read(newsockfd) will return 0 to indicate that the connection has closed. At that point, the server should close(newsockfd), print your "Client has gone away message", and not use newsockfd anymore (i.e. either the server program should exit, or, more usefully, it should just break out of its while(1)-loop and go back to calling accept() again, so that the next time a client runs it too can connect to the server)
my program only works as read operation for server and write operation for client side.How can I do read and write operations for both client and server using multithreading concept.
I'm able to write message on client side but not able to write on server side. please help me to solve this problem.
/*server function*/
int server(int argc,char *argv[])
{
int sock_fd,socknew_fd,portNo,cliLen;//socket file descriptor-sock_fd
char buff[256];
struct sockaddr_in serv_addr,cli_addr;
int n;
/*first call to socket function*/
sock_fd=socket(AF_INET,SOCK_STREAM,0); /*socket created of family type IP v4 ,socket type TCP and 0 indicates default protocol to be selected*/
if(sock_fd<0) //if -1(sock_fd) returned by socket() it shows socket cant be created
{
perror("error opening socket");
exit(0);
}
/*initialize socket structure*/
bzero((char *)&serv_addr,sizeof(serv_addr));//setting all default structure socket values to 0
portNo=atoi(argv[1]);
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr.s_addr=INADDR_ANY;
serv_addr.sin_port=htons(portNo);
//initialize family,server address,portno which should be of network order
/*now bind the host address using bind() call*/
if(bind(sock_fd,(struct sockaddr *) &serv_addr,sizeof(serv_addr))<0)
{perror("error in binding");
exit(1);
}
/*start listening for client and be in sleep mode till any request arises from client*/
while(1)
{
listen(sock_fd,5);
cliLen=sizeof(cli_addr);
/*accept actual connection from client*/
socknew_fd=accept(sock_fd,(struct sockaddr *) &cli_addr,&cliLen);
if(socknew_fd<0)
{
perror("error in accept");
exit(1);
}
/*if connection is established start communicating*/
bzero(buff,256);
n=read(socknew_fd,buff,255);
if(buff[0]==32)
break;
if(n<0)
{perror("error in reading from socket");
exit(1);
}
printf("here is message:%s\n",buff);
/*write a response to client*/
n=write(socknew_fd,"I got your message",18);
if(n<0)
{perror("error writing in socket");
exit(1);
}
}
return 0;
}
For instance, there are several requests in a file, and I read them then send to server line by line by using write function. However, there is only one response from server, and I cannot read the whole requests to server. Is there anyone who can help me to figure out this problem. Thank you so much!
There is server code:
<pre> <code>
int main(int argc, char *argv[]){
int sockfd, newsockfd, n;
unsigned int clientLen;
char bufferSK[256];
struct sockaddr_in serv_addr,cli_addr;
FILE *fp = NULL;
//create an endpoint for bind, listen and accept.
sockfd = socket(AF_INET,SOCK_STREAM,0);
if (sockfd < 0) {
printf("Failed to create socket for server!\n");
}
bzero((char *)&serv_addr, sizeof(serv_addr));
//set the address of server.
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(port_number);
//bind the port with server address
if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
printf("Error on bind!\n");
}
listen(sockfd,port_number);
printf("\nI am listening for connection\n");
clientLen = sizeof(cli_addr);
//using accept function to accept the connection from client
newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clientLen);
if (newsockfd < 0) {
printf("Error on accept!\n");
}
printf("\nI have accepted your connection\n");
bzero(bufferSK,256);
n = read (newsockfd, bufferSK,255);
if (n < 0) {
printf("Error reading message from socket\n");
}
printf("\nThe message from client is: %s",bufferSK);
n = write(newsockfd, "SERVER: I got your message!\n", 27);
if (n < 0) {
printf("Error writing to socket\n");
}
close(newsockfd);
close(sockfd);
return 0;
}
there is client code:
<pre> <code>
FILE *fp_queue;
int main(int argc, char *argv[]){
int sockfd, server_port_number, n, connectRes;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
//Three parameters must be provided.
if(argc != 4){
fprintf(stderr, "Usage: %s server_host_name server_port_number file_path\n",argv[0]);
exit(0);
}
server_port_number = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
//create socket for client.
if (sockfd < 0) {
printf("Failed to create socket for client\n");
exit(0);
}
server = gethostbyname(argv[1]);
if (server == NULL) {
printf("Oops! There is no such host!\n");
exit(0);
}
//set the attributes of server as zeros.
bzero((char *)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
//copy the server address from serv_addr.sin_addr.s_addr to server->h_adddr.
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(server_port_number);
connectRes = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (connectRes < 0) {
printf("Error connection\n");
exit(0);
}
printf("connect successfully\n");
fp_queue = fopen(argv[3], "r");
if (fp_queue == NULL) {
printf("Failed open client file %s\n", argv[3]);
exit(1);
}
bzero(buffer, 256);
while ((fgets(buffer,sizeof(buffer),fp_queue)) != NULL) {
buffer[strlen(buffer) - 1] = '\0';
printf("buffer is %s\n", buffer);
n = write(sockfd, buffer, strlen(buffer));
if (n < 0) {
printf("Error write to socket\n");
}
bzero(cliBuffer, 256);
n = read(sockfd, buffer, 256);
if (n <0) {
printf("Error read from socket\n");
}
printf("%s\n", buffer);
}
close(sockfd);
return 0;
}
There are at least 2 design issues in the code.
The server code receives one request, sends a response and then server terminates. If you want to process more requests over one connection then the server code must contain a loop like a client has. The server code should contain something like
while ((n = read (newsockfd, bufferSK, 255) > 0) {
printf("\nThe message from client is: %s",bufferSK);
n = write(newsockfd, "SERVER: I got your message!\n", 27);
if (n < 0) {
printf("Error writing to socket\n");
break;
}
}
close(newsockfd);
The next problem is that TCP is a stream oriented protocol and your code does not consider that. The stream orientation means that protocol does not keep message boundaries. When a sender calls write("a"); write("b") the receiver may get characters in two separate reads or it may receive 2 characters in one read. To overcome the problem the peers must define some protocol how to determine message boundaries. Usually client sends a message length at begin of message or a control character is used as message boundary or messages have fixed length.
I have a server-client system (concurrent server). I have different clients on different machines. I am trying to send a notification to particular clients. However, I have a problem as the clients all have the same socket descriptor. On both computers, the clients have a socket descriptor of 3 and at the server a sd of 5. Can someone please tell me how I can identify these different clients and why is this happening?
int main(int argc, char *argv[]) {
pid_t pid;
int buff_size = 1024;
char buff[buff_size];
int listen_fd, client_conn;
struct sockaddr_in serv_addr;
int server_port = 5001;
char remote_file[255];
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd < 0) {
perror("Socket cannot be opened");
exit(1);
}
/*Turning off address checking in order to allow port numbers to be
reused before the TIME_WAIT. Otherwise it will not be possible to bind
in a very short time after the server has been shut down*/
int on = 1;
int status = setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR,
(const char *) &on, sizeof(on));
if (status == -1) {
perror("Failed to Reuse Address on Binding");
}
// Initialise socket structure
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY; // Accept connections from any address
serv_addr.sin_port = htons(server_port);
// Bind the host address
if (bind(listen_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr))
< 0) {
perror("ERROR on binding");
exit(1);
}
// Start listening for the clients, here process will
// go in sleep mode and will wait for the incoming connection
listen(listen_fd, 5);
while (1) {
//Accepting client connection
client_conn = accept(listen_fd, (struct sockaddr *) NULL, NULL);
if (client_conn < 0) {
perror("Client was not accepted...");
exit(1);
}
if ((pid = fork()) == 0) {
close(listen_fd);
bzero(buff, buff_size);
while ((bytes_read = read(client_conn, buff, buff_size)) > 0) {
fclose(file);
}
}
//Terminating child process and closing socket
close(client_conn);
exit(0);
bzero(buff, buff_size);
}
//parent process closing socket connection
close(client_conn);
}
return 0;
}
After the server forks a child it does close(client_conn). When accept assigns a socket descriptor to the new connection, it uses the lowest closed descriptor. Since you closed the socket earlier, it can be used for the next client that comes in.
This isn't a problem, because the connections are being managed by the child processes. They each have their own descriptor 5, and they don't interfere with each other.
You can get the client address & port returned to you by accept. Currently you are passing a null
client_conn = accept(listen_fd, (struct sockaddr *) NULL, NULL);
however just add a few lines like
struct sockaddr_in serv_addr, cli_addr;
int len = sizeof(cli_addr);
client_conn = accept(listen_fd, (struct sockaddr *) &cli_addr, &len);
and you have the client info in cli_addr.sin_addr.s_addr and cli_addr.sin_port.
You can get the pid of the child processing the connection from the return code of fork. That should give you all the information you need to create a table.
I have the following code (I'm working from code at http://www.linuxhowtos.org/C_C++/socket.htm) which I'm trying to turn into a proxy server:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void dostuff(int); /* function prototype */
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
//setup proxy:
int sockfd, newsockfd, portno, pid;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
if (argc < 2) {
fprintf(stderr,"***ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("***ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("***ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
while (1) {
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("***ERROR on accept");
pid = fork();
if (pid < 0)
error("***ERROR on fork");
if (pid == 0) {
close(sockfd);
dostuff(newsockfd);
exit(0);
}
else close(newsockfd);
} /* end of while */
close(sockfd);
return 0; /* we never get here */
}
/******** DOSTUFF() *********************
There is a separate instance of this function
for each connection. It handles all communication
once a connnection has been established.
*****************************************/
void dostuff (int sock)
{
int n;
char buffer[256];
bzero(buffer,256);
n = read(sock,buffer,255);
if (n < 0){
error("***ERROR reading from socket");
}
//printf("Here is the message: %s\n",buffer);
/*
***Forward message to port 80 and read response here
*/
n = write(sock,"I got your message",18);
if (n < 0) error("***ERROR writing to socket");
}
In the function "dostuff" I want to write 'buffer' to port 80, read the response and write this response back over port 20000 (argv[1]).
At the moment, when I set my browser's proxy to 172.16.1.218:20000, all I get is "I got your message". I want to change this to the response from the webpage!
Any pointers in the right direction greatly appreciated.
Here's what I've tried sofar (replace multi-line comment "Forward message to port 80 and read response here" with this code):
int sockfdi, portnoi, ni;
struct sockaddr_in serv_addri;
struct hostent *serveri;
portnoi =80;
sockfdi = socket(AF_INET, SOCK_STREAM, 0);
if (sockfdi < 0){
error("***ERROR opening socket");
}
serveri = gethostbyname("172.16.1.218");
if (serveri == NULL){
fprintf(stderr,"***ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addri, sizeof(serv_addri));
serv_addri.sin_family = AF_INET;
bcopy((char *)serveri->h_addr, (char *)&serv_addri.sin_addr.s_addr, serveri->h_length);
serv_addri.sin_port = htons(portnoi);
if (connect(sockfdi,(struct sockaddr *) &serv_addri,sizeof(serv_addri)) < 0){
error("***ERROR connecting");
}
printf("Please enter the message: ");
bzero(buffer,256);
But every time I try to connect via my webbrowser, the server echos: "***ERROR connecting: Connection refused"
Many thanks in advance,
This is a non-trivial task you set out to do. Currently, you're missing three things, an easy one and two difficult ones:
You have to open a network connection to the server you want to forward the call to (rather easy, see socket() and connect()).
You'll then have a duplex connection, that is two concurrent streams of data, one going from the client to the forwarded server and one from the forwarded server to the client. In order to cope with this concurrency, you either need two threads with blocking I/O or some sort of non-blocking I/O (see select() or AIO).
If you forward an HTTP request without changes to another server, you'll likely end up with invalid server names and IP addresses in the request. The request will then be rejected. So you'll need to parse the HTTP header, do some replacements and forward the modified HTTP request.