closing socket in BSD sockets - c

My code is :
int main(int argc, char *argv[])
{
int sockfd, new_fd; /* listen on sock_fd, new connection on new_fd */
struct sockaddr_in my_addr; /* my address information */
struct sockaddr_in their_addr; /* connector's address information */
socklen_t sin_size;
/* generate the socket */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
/* generate the end point */
my_addr.sin_family = AF_INET; /* host byte order */
my_addr.sin_port = htons(MYPORT); /* short, network byte order */
my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */
/* bzero(&(my_addr.sin_zero), 8); ZJL*/ /* zero the rest of the struct */
/* bind the socket to the end point */
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) \
== -1) {
perror("bind");
exit(1);
}
/* start listnening */
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
printf("server starts listnening %d...\n",sockfd);
/* repeat: accept, send, close the connection */
/* for every accepted connection, use a sepetate process or thread to serve it */
while(1) { /* main accept() loop */
sin_size = sizeof(struct sockaddr_in);
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, \
&sin_size)) == -1) {
perror("accept");
continue;
}
printf("server: got connection from %s\n", \
inet_ntoa(their_addr.sin_addr));
if ((numbytes=recv(new_fd, buf, MAXDATASIZE, 0)) == -1) {
perror("recv");
exit(1);
}
buf[numbytes] = '\0';
printf("Received: %s",buf);
if (send(new_fd, "Hello, world!\n", MAXDATASIZE, 0) == -1)
perror("send");
close(new_fd);
exit(0);
close(new_fd); /* parent doesn't need this */
while(waitpid(-1,NULL,WNOHANG) > 0); /* clean up child processes */
}
return 0;
}
So whenever I execute this server, after one client uses that it terminates. But If I want to execute it again lets say within 60 seconds, then it gives an error of bind: Address already in use I thought the close() function actually releases the socket so that it would be available to use it again instantly. So what am I missing here?

Before calling bind, you can mark that you want to potentially reuse an address/port using the SO_REUSEADDR socket option:
int reuseaddr = 1;
int err = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
&reuseaddr, sizeof(reuseaddr));

Also, I don't see where BACKLOG is defined, which you use in the listen() call. If this is by chance set to 1, you may want to increase it. Then, while the last socket closes, you can be handling the next call.

Firstly the original form of this code comes from Beej's guide
You have supplied code which is either very wrong or edited for brevity. After sending the "Hello World" response you call exit(0); Please add curly braces.
if (send(new_fd, "Hello, world!\n", MAXDATASIZE, 0) == -1)
perror("send");
close(new_fd);
exit(0);
Beej;s code:
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
if (send(new_fd, "Hello, world!", 13, 0) == -1)
perror("send");
close(new_fd);
exit(0);
}
close(new_fd); // parent doesn't need this`
May I also point out that Beej's code and yours does not handle the event where 'recv' returns 0 in the case a connection was lost or aborted by the client. On a side note remember a call to recv will block.
if ((numbytes=recv(new_fd, buf, MAXDATASIZE, 0)) == -1) {
perror("recv");
exit(1);
}
While this seems it probably wont affect the crash this particular issue may cause unexpected crashes later when the client is closed unexpectedly.

Delay is due to TIME_WAIT
In the process of terminating a connection, the important thing to keep in mind is that the application process on both sides of the connection must independently close its half of the connection. Due to the Three Way Handshake policy of a TCP connection,kernel waits for the acknowledgment that the connection on the other side is also closed
However, You can override this functionality by following methods:
Method 1
In the /etc/sysctl.conf file, add the following lines to persist it after reboot:
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
Method 2
echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse

Related

TCP server that listen on two different ports

I have a TCP server that is listening on two different ports . I created two different sockets one on port 8888 and one on port 6634. I listen on those ports and then i add the two sockets in FD_SET and pass them to select() function ...
When a socket is ready to read i check with FD_ISSET to see on which port i have message to read .
any way when i connect to port 8888 the conception is successful and i can send towards the server and receive ... when i ctrl+c the client the select function is returning again 1 and now my accept() fails ...
when i do the same thing on port 6634 everything is ok... the code stops at the select() and waits for a socket to be ready to read!
can anyone tell me WHY is this happening ?
take a look at my code in attachment
int main()
{
SOCKET conn_request_skt; /* socket where connections are accepted */
char buf[RBUFLEN], buf1[RBUFLEN]; /* reception buffer */
uint16_t lport_n, lport_h, lport_n1, lport_h1; /* port where the server listens (net/host byte ord resp.) */
int bklog = 2; /* listen backlog */
SOCKET s,s1;
int result, n;
socklen_t addrlen;
struct sockaddr_in saddr, caddr; /* server and client address structures */
int optval,childpid,i; /* flag value for setsockopt */
int connectcnt; /* number of connection requests */
fd_set readfds;
/* Initialize socket API if needed */
SockStartup();
/* input server port number */
lport_h=6634;
lport_n = htons(lport_h);
lport_h1=8888;
lport_n1 = htons(lport_h1);
/* create the socket */
printf("Creating first socket\n");
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET)
err_fatal("socket() failed");
printf("done, socket number %u\n",s);
/* bind the socket to any local IP address */
saddr.sin_family = AF_INET;
saddr.sin_port = lport_n;
saddr.sin_addr.s_addr = INADDR_ANY;
showAddr("Binding to address first socket", &saddr);
result = bind(s, (struct sockaddr *) &saddr, sizeof(saddr));
if (result == -1)
err_fatal("bind() failed");
printf("done.\n");
printf("Creating second socket\n");
s1 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s1 == INVALID_SOCKET)
err_fatal("socket() failed");
printf("done, socket number %u\n",s1);
/* bind the socket to any local IP address */
saddr.sin_port=lport_n1;
showAddr("Binding to address second socket", &saddr);
result = bind(s1, (struct sockaddr *) &saddr, sizeof(saddr));
if (result == -1)
err_fatal("bind() failed");
printf("done.\n");
/* listen */
printf ("Listening at socket %d with backlog = %d \n",s,bklog);
result = listen(s, bklog);
if (result == -1)
err_fatal("listen() failed");
printf("done.\n");
printf ("Listening at socket %d with backlog = %d \n",s1,bklog);
result = listen(s1, bklog);
if (result == -1)
err_fatal("listen() failed");
printf("done.\n");
for (;;)
{
FD_ZERO(&readfds); /* initialize the fd set */
FD_SET(s, &readfds);
FD_SET(s1, &readfds); /* add socket fd */
printf("here \n");
printf("result bifore select is %d \n", result);
result=select(s1+1, &readfds, 0, 0, 0);
printf("result after select is %d \n", result);
if(result<0)
{
err_fatal("select() failed");
}
if(result>0)
{
if(FD_ISSET(s,&readfds))
{
conn_request_skt=s;
/* accept next connection */
addrlen = sizeof(struct sockaddr_in);
s = accept(conn_request_skt, (struct sockaddr *) &caddr, &addrlen);
if (s == INVALID_SOCKET)
err_fatal("accept() failed");
showAddr("Accepted connection from", &caddr);
printf("new socket: %u\n",s);
/* serve the client on socket s */
for (;;)
{
n=recv(s, buf, RBUFLEN-1, 0);
if (n < 0)
{
printf("Read error\n");
closesocket(s);
printf("Socket %d closed\n", s);
break;
}
else if (n==0)
{
printf("Connection closed by party on socket %d\n",s);
//closesocket(s);
break;
}
else
{
printf("Received line from socket %03d :\n", s);
buf[n]=0;
printf("[%s]\n",buf);
if(writen(s, buf, n) != n)
printf("Write error while replying\n");
else
printf("Reply sent\n");
}
}
}
if(FD_ISSET(s1,&readfds))
{
conn_request_skt=s1;
/* accept next connection */
addrlen = sizeof(struct sockaddr_in);
printf("bifore accept! \n");
s1 = accept(conn_request_skt, (struct sockaddr *) &caddr, &addrlen);
if (s1 == INVALID_SOCKET)
err_fatal("accept() failed");
showAddr("Accepted connection from", &caddr);
printf("new socket: %u\n",s1);
/* serve the client on socket s */
for (;;)
{
n=recv(s1, buf, RBUFLEN-1, 0);
if (n < 0)
{
printf("Read error\n");
closesocket(s1);
printf("Socket %d closed\n", s1);
break;
}
else if (n==0)
{
printf("Connection closed by party on socket %d\n",s1);
//closesocket(s);
break;
}
else
{
printf("Received line from socket %03d :\n", s1);
buf[n]=0;
printf("[%s]\n",buf);
if(writen(s1, buf, n) != n)
printf("Write error while replying\n");
else
printf("Reply sent\n");
}
}
}
}
}
}
The first listener socket is created with:
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
And then the data socket is accepted with:
conn_request_skt=s;
s = accept(conn_request_skt, (struct sockaddr *) &caddr, &addrlen);
See? The next loop, when you are going to select over the listener socket, s no longer holds that socket, but the (closed) data socket.
The solution is to use different variables for the listener socket and the data socket (conn_request_skt is just obfuscating the issue).
You are overwriting your socket variable s1 with the result of the accept() call. So s1 contains now the descriptor of the socket you are actually reading from. Then you close that socket. But in the next pass of the main loop, you check for readability on that (now closed) descriptor, which does not work.
I believe it would be better not to reuse variables in this case. Use a new variable for the actual connection socket, so that you retain the original listening socket in s1.

Handling TCP out-of-band data correctly

I wrote a simple client and server to work with out-of-band data. The client just sends a single out of band data to the server and the server uses SIGURG to handle this single byte. The server also should handle normal traffic in an infinite loop. The code has a race condition which does not work as expected. Sometimes I get an "Invalid argument" from a call to recv() in the SIGURG handler. Another question I have is that should I block SIGURG signal when calling accept? Also, which one is the preferred scenario:
install SIGURG handler and set the socket owner for the listening socket before calling accept.
install SIGURG handler and set the socket owner for the connected socket after calling accept.
if none of the above, please write your suggestion.
My last question is, since the client sends the out-of-band data immediately, is there a chance for the server to receive the SIGURG just after the completion of three-way handshake, but before returning from accept? If so, I think the "clifd" var can has an invalid value when it is used in the SIGURG handler.
the code for the client:
#include "myheader.h"
int main(int argc, char *argv[])
{
struct sockaddr_in saddr;
int sockfd;
const char c = 'a';
if (2 != argc)
{
fprintf(stderr, "Usage: %s ipaddr\n", argv[0]);
exit(EXIT_FAILURE);
}
if (-1 == (sockfd = socket(AF_INET, SOCK_STREAM, 0)))
die("sockfd()");
(void)memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(PORT);
if (-1 == inet_pton(AF_INET, argv[1], &saddr.sin_addr))
die("inet_pton()");
if (-1 == connect(sockfd, (struct sockaddr*)&saddr, sizeof(saddr)))
die("connect()");
// if (-1 == send(sockfd, "HELLO\n", 6, 0))
// die("send()");
if (-1 == send(sockfd, &c, 1, MSG_OOB))
die("send()");
close(sockfd);
return 0;
}
and the code for the server:
#include "myheader.h"
void sigurg_handler(int);
char oob;
int sockfd, clifd;
int main(void)
{
struct sockaddr_in myaddr;
char buf[BUFSIZ];
ssize_t nbytes;
sigset_t sset, oset;
sigemptyset(&sset);
sigaddset(&sset, SIGURG);
if (-1 == (sockfd = socket(AF_INET, SOCK_STREAM, 0)))
die("socket()");
(void)memset(&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(PORT);
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (-1 == bind(sockfd, (struct sockaddr*)&myaddr, sizeof(myaddr)))
die("bind()");
if (-1 == listen(sockfd, BACKLOG))
die("listen()");
if (-1 == fcntl(sockfd, F_SETOWN, getpid()))
die("fcntl()");
if (SIG_ERR == signal(SIGURG, sigurg_handler))
die("signal()");
for (;;)
{
/* block SIGURG when accepting the connection */
// sigprocmask(SIG_SETMASK, &sset, &oset);
printf("bloking in accept()\n");
if (-1 == (clifd = accept(sockfd, NULL, NULL)))
die("accept()");
/* unblock SIGURG */
// sigprocmask(SIG_SETMASK, &oset, NULL);
printf("recv()ing normal data\n");
nbytes = recv(clifd, buf, sizeof(buf), 0);
buf[nbytes] = 0; /* null-terminate */
printf("%s", buf);
}
close(sockfd);
}
void
sigurg_handler(int signo)
{
char buff[100];
ssize_t nbytes;
printf("SIGURG received\n");
if (clifd != 0)
{
if (-1 == (nbytes = recv(clifd, buff, sizeof(buff) - 1, MSG_OOB)))
die("recv() in sigurg_handler()");
buff[nbytes] = 0;
printf("from sigurg_handler: received \"%s\"\n", buff);
}
else
{
printf("clifd = %d\n", clifd);
exit(1);
}
}
Example:
> ./serv
bloking in accept() /* first client */
SIGURG received
from sigurg_handler: received "a"
recv()ing normal data
bloking in accept() /* second client */
SIGURG received
recv() in sigurg_handler(): Invalid argument
> ./serv /* third client */
bloking in accept()
SIGURG received
clifd = 0
>
I heard select() third parameter can handle tcp OOB
ret = select(connfd+1,&read_fds,NULL,&exceptions_fds,NULL);
https://blog.csdn.net/ty_laurel/article/details/52164669
https://github.com/ty92/OOB
select() exceptional
use select really can avoid the signal setup step,
so that you not miss the oob (that before signal setup).
https://man7.org/linux/man-pages/man7/tcp.7.html#:~:text=out%2Dof%2Dband%20data%20is%20present
man 2 select_tut has a demo code
https://man7.org/linux/man-pages/man2/select_tut.2.html#:~:text=read%20OOB%20data,-before
limitation
but if you did't read the oob byte in time, when new oob arrive, old oob byte become normal data (inserted as normal data into the stream), even if SO_OOBINLINE not set (on linux)
//that behavior may difference in various tcp stack.
https://man7.org/linux/man-pages/man7/tcp.7.html#:~:text=limited%20support%20for%20out%2Dof%2Dband
PS: you'd better copy links with :~:text= manually, it'll highlight the keyword in chrome.
// or click in edit preview mode.
// in normal page stackoverflow always encode ~ in url, which will invalidate the anchor
// those man pages still not support anchors to this day, it's pity.

Why won't my server implementation run concurrently properly?

I am attempting to create a client/server system that can handle multiple concurrent connections using the unix system call fork.
The client enters a movie title, and the server will check if the movie was there or not. If it was there, it would tell the client the ranking, the name, and the box records.
looking at my forking implementation, the client asks for user input, however the program just simply goes pass it.
OUTPUT EXAMPLE:
connection made with client 127.0.0.1
PID IS 27270
--> all messages read - connection being closed
CLIENT: Please input an string: PID IS 0
At this line, CLIENT: Please input an string: PID IS 0, the user was suppose to input a string, however the program glances over it. How do I make the program take in the string from the client?
SERVER CODE:
int main()
{
int sock, clientsock, mlen, addrsize, msgct, chc, chct, pid;
struct sockaddr_in addr; //ipv4 address
char ch, buf[80];
/*
* Create a socket.
*/
sock = socket(AF_INET, SOCK_STREAM,0); //create socket (AF_NET shows its ipv4 internet connection, SOCK_STREAM shows its a tcp)
if (sock == -1)
{
perror("opening socket");
exit(-1);
}
//Bind socket to local address
/*
* Bind a name to the socket. Since the server will bind with
* any client, the machine address is zero or INADDR_ANY. The port
* has to be the same as the client uses.
*/
addr.sin_family = AF_INET;
addr.sin_port = htons (32351); //port number for local address
addr.sin_addr.s_addr = htonl (INADDR_ANY); //ip address (you can also hard code it)
if (bind(sock, (struct sockaddr *) &addr, //binding, first parameter : is the socket you created, &addr is the
sizeof (struct sockaddr_in)) == -1) //error checking
{
perror ("on bind");
exit (-1);
} //(at this moment we have binded socket)
/*
* Make the socket available for potential clients.
*/
//if there is connection or not?
if (listen(sock,1) == -1)
{
perror("on listen");
exit(-1);
}
//-------Text File Implementation-----------
FILE *fp;
char data[5][200];
char rank[5][2];
char name[5][255];
char value[5][100];
/* opening file for reading */
fp = fopen("movie.txt", "r");
if(fp == NULL) {
perror("Error opening file");
return(-1);
}
fgets (data[0], 200, fp);
int i = 1;
while(fgets (data[i], 200, fp)!=NULL)
{
/* writing content to stdout */
sscanf(data[i],"%s %[^$] %s",rank[i],name[i],value[i]);
puts(data[i]);
i+=1;
}
//CODE DOES NOT IMPLEMENT AFTER THIS WHILE LOOP
//close the file
fclose(fp);
addrsize = sizeof(struct sockaddr_in);
//THIS WHILE LOOP IS NOT BEING IMPLEMENTED...
while(1)
{
clientsock = accept(sock, (struct sockaddr *) &addr, &addrsize);
if (clientsock == -1)//error checking
{
perror("on accept");
exit(-1);
}
printf("connection made with client ");
printf ("%s\n", inet_ntoa (addr.sin_addr)); //also print client address
/* Create child process */
pid = fork();
if (pid < 0)
{
perror("ERROR on fork");
exit(1);
}
if (pid == 0)
{
/* This is the client process */
close(sock);
bool exist = false;
mlen = recv (clientsock, buf, 80, 0);
if (mlen < 0)
{
perror("ERROR reading from socket");
exit(1);
}
int lenS;
int which;
for(int i = 1; i<5; i++)
{
printf("%s\n\n", name[i]);
char *pch = strstr(name[i],buf);
if(pch != NULL)
{
which = i;
exist = true;
puts("GOOD");
}
else
{
puts("bad");
}
}
if(exist)
{
//SEND TO CLIENT FROM HERE!
printf("%s\n", rank[which]);
printf("%s\n", name[which]);
printf("%s\n", value[which]);
lenS = strlen(name[which]);
send (clientsock, name[which], lenS+1, 0);
}
else
{
//SEND TO CLIENT FROM HERE!!!!
printf("NOT HERE ");
send (clientsock, "NOT HERE", 9, 0);
}
printf("Here is the message: %s\n",buf);
exit(0);
}
else
{
close(clientsock);
printf(" --> all messages read - connection being closed\n");
}
}
}
CLIENT CODE:
int main()
{
int sock, addrsize;
struct sockaddr_in addr;
unsigned int in_address;
char buf[80];
int mlen;
/*
* Open a socket for Internet stream services.
*/
sock = socket(AF_INET, SOCK_STREAM,0); //creating a socket to connect to server, AF_INET : ipv4 internet connection, SOCK_STREAM tcp
if (sock == -1)
{ perror("opening socket");
exit(-1);
}
addr.sin_family = AF_INET;
addr.sin_port = htons (32351); //port number has to be the same as the one from server
in_address = 127 << 24 | 0 << 16 | 0 << 8 | 1; //ip address, local host, since we are running client and server on the same computer, it needs to have the same ip address
addr.sin_addr.s_addr = htonl (in_address);
if (connect (sock, (struct sockaddr *) &addr, //binding
sizeof (struct sockaddr_in)) == -1)
{
perror("on connect");
exit(-1);
}
char word[100];
int len;
printf("CLIENT: Please input an string: ");
scanf("%s", word);
//printf("You entered: %s\n", word);
len = strlen(word);
send (sock, word, len+1, 0);
mlen = recv (sock, buf, 80, 0);
printf ("%s\n\n\n\n\n\n\n", buf);
/*
* Do a shutdown to gracefully terminate by saying - "no more data"
* and then close the socket -- the shutdown is optional in a one way
* communication that is going to terminate, but a good habit to get
* into.
*/
if (shutdown(sock, 1) == -1)
{
perror("on shutdown");
exit(-1);
}
printf ("Client is done\n");
close(sock);
}
You are running the client and server programs on the same machine, with the same controlling terminal. The server master process, its client-service subprocess(es), and the independent client process therefore may all write to that terminal. They run independently and concurrently, so their outputs can be mashed up.
The fact that the PID IS 0 message is emitted after the prompt does not indicate that the client program has skipped accepting input, which indeed, I don't see how it could do. The prompt and the PID message come from different processes.
It would make things clearer to launch the server process and the client process from separate (virtual) terminals, so that their output is not mixed.

Limiting Clients From Connecting

Trying to limit the amount of client connections in my client-server c application. This is what I have, however it doesn't work. (Doesn't even recognise when max_connections is reached. How can I fix this?
int main(int argc, char *argv[])
{
//fill db
if (obtainDb() == false) {
printf("Database obtain error.\n");
exit(true);
}
//initialise variables
total_connections = 0;
/* generate the socket */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(true);
}
/* generate the end point */
my_addr.sin_family = AF_INET; // host byte order
my_addr.sin_port = htons(MYPORT); // short, network byte order
my_addr.sin_addr.s_addr = INADDR_ANY; // auto-fill with my IP
/* bind the socket to the end point */
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) \
== -1) {
perror("bind");
exit(true);
}
/* start listnening */
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(true);
}
printf("server starts listnening ...\n");
while(true){
sin_size = sizeof(struct sockaddr_in);
if (total_connections == max_connections) {
printf("Max Number of clients connected!\n");
while(total_connections == max_connections);
}
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, \
&sin_size)) == -1) {
perror("accept");
continue;
}
total_connections++;
printf("server: got connection from %s\n", \
inet_ntoa(their_addr.sin_addr));
userInput();
while(waitpid(-1,NULL,WNOHANG)>0);
}
return false;
}
Thanks
Edit: UserInput():
void userInput(void) {
if (!fork()) { // this is the child process
while(true){
char buffer[MAXDATASIZE];
char res[MAXDATASIZE];
memset(buffer, '\0', MAXDATASIZE);
memset(res, '\0', sizeof(res));
if ((numbytes=recv(new_fd, buffer, sizeof(buffer), 0)) == -1) {
perror("recv");
exit(true);
}
if (numbytes == 0) {
printf("client left");
close(new_fd);
total_connections--;
exit(false);
}
buffer[numbytes] = '\0'; // add null terminator
printf("Request: %s\n",buffer);
search(buffer,res);
}
close(new_fd); // parent doesn't need this
exit(false);
}
close(new_fd);
}
When you fork all variables are copied to the new process. That means that the children have their own copy of total_connections.
Instead of using a variable, you should use wait to find out whether any children have exited.
Forking creates a new instance of your proces, which also means that each variable is copied to the new process. Your initial total_connections will actually never get increased beyond 1.
C fork dealing with global variable
A relatively simple option would be to use threads instead of processes for handling multiple clients simultaneously.

Linux TCP server, sending RAW data to few clients every X seconds

I'm writing simple TCP server and I found some issue. Maybe you can help me a bit.
So, I wrote an echo server first (to test connection with computer client). It's working okay, but now I need to change it a bit. Server should sent char[100] to client when it connects and sent same char[] to every client every X seconds/minutes.
I've trying many changes, but application only crashes. Commented some of my "mistakes" in this code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
/* BufferLength is 100 bytes */
#define BufferLength 100
/* Server port */
#define SERVPORT 6000
int main(){
/* Variable and structure definitions. */
int sd, wyslij, sd2, rc, length = sizeof(int);
int totalcnt = 0, on = 1;
char temp;
char buffer[BufferLength];
struct sockaddr_in serveraddr;
struct sockaddr_in their_addr;
fd_set read_fd;
struct timeval timeout;
timeout.tv_sec = 15;
timeout.tv_usec = 0;
char datadata[100] = "This is a test string from server lol!!! ";
/* Get a socket descriptor */
if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
perror("Server-socket() error");
/* exit */
exit (-1);
}else
printf("Server-socket() is OK\n");
/* Allow socket descriptor to be reusable */
if((rc = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))) < 0){
perror("Server-setsockopt() error");
close(sd);
exit (-1);
}else
printf("Server-setsockopt() is OK\n");
/* bind to an address */
memset(&serveraddr, 0x00, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERVPORT);
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
printf("Using %s, listening at %d\n", inet_ntoa(serveraddr.sin_addr), SERVPORT);
if((rc = bind(sd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))) < 0){
perror("Server-bind() error");
/* Close the socket descriptor */
close(sd);
/* and just exit */
exit(-1);
}else
printf("Server-bind() is OK\n");
/* queue up to 10 clients */
if((rc = listen(sd, 10)) < 0){
perror("Server-listen() error");
close(sd);
exit (-1);
}else
printf("Server-Ready for client connection...\n");
/* accept() the incoming connection request. */
int sin_size = sizeof(struct sockaddr_in);
if((sd2 = accept(sd, (struct sockaddr *)&their_addr, &sin_size)) < 0){
perror("Server-accept() error");
close(sd);
exit (-1);
}else
printf("Server-accept() is OK\n");
/*client IP*/
printf("Server-new socket, sd2 is OK...\n");
printf("Got connection from the client: %s\n", inet_ntoa(their_addr.sin_addr));
/* Wait for up to 15 seconds on */
/* select() for data to be read. */
FD_ZERO(&read_fd);
FD_SET(sd2, &read_fd);
rc = select(sd2+1, &read_fd, NULL, NULL, &timeout);
/* rc = write(sd2, datadata, sizeof(datadata)); */
if((rc == 1) && (FD_ISSET(sd2, &read_fd))){
/* rc = write(sd2, datadata, sizeof(datadata)); */
/* Read data from the client. */
totalcnt = 0;
while(totalcnt < BufferLength){
/* read() from client */
rc = read(sd2, &buffer[totalcnt], (BufferLength - totalcnt));
if(rc < 0){
perror("Server-read() error");
close(sd);
close(sd2);
exit (-1);
}else if (rc == 0){
printf("Client program has issued a close()\n");
close(sd);
close(sd2);
exit(-1);
}
else{
totalcnt += rc;
printf("Server-read() is OK\n");
}
}
}else if (rc < 0){
perror("Server-select() error");
close(sd);
close(sd2);
exit(-1);
}
/* rc == 0 */
else{
printf("Server-select() timed out.\n");
close(sd);
close(sd2);
exit(-1);
}
/* Shows the data */
printf("Received data from the client: %s\n", buffer);
/* write() some bytes of string, */
/* back to the client. */
printf("Server-Echoing back to client...\n");
rc = write(sd2, datadata, sizeof(datadata));
if(rc != totalcnt){
perror("Server-write() error");
/* Get the error number. */
rc = getsockopt(sd2, SOL_SOCKET, SO_ERROR, &temp, &length);
if(rc == 0){
/* Print out the asynchronously */
/* received error. */
errno = temp;
perror("SO_ERROR was: ");
}else
printf("Server-write() is OK\n");
close(sd);
close(sd2);
exit(-1);
}
/* Close the connection to the client and */
/* close the server listening socket. */
close(sd2);
close(sd);
exit(0);
return 0;
}
Thanks a lot buddies!
You may want to check out D.J. Bernstein's tcpserver (see http://cr.yp.to/ucspi-tcp/tcpserver.html). Basically, you can simply run your C program under tcpserver, and tcpserver will handle everything as far as setting up the sockets, listing for incoming connections on whatever port you are using, etc. When an incoming connection arrives on the port that you specify, tcpserver will spawn an instance of your program and pipe incoming info from the client to your program's STDIN, and pipe outgoing info from your program's STDOUT back to the client. This way, you can concentrate on your program's core logic (and simply read/write to stdout/stdin), and let tcpserver handle all of the heavy lifting as far as the sockets, etc.
Well, I ran your program against a simple TCP client code and did not see any crash. So, you probably should add gdb info to that. Also, in the program, I don't see where your programs wakes up periodically (you do have a comment) and sends data to the client. You should also consider adding the client fd to the list of read fd set and have one common select() call. If the select() returns a read-event on the listener, then that is a new connection and you should call accept. If the select() returns a read-event on a child fd, then you have some data to read adn you should call recv()/read().

Resources