Testing a TCP/IP server locally - c

I have written an echo TCP server in C.
I wish to test my code to see if it works.
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#define BUF_SIZE 500
#define LISTEN_BACKLOG 50
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int
main(int argc, char *argv[])
{
struct addrinfo hints;
struct addrinfo *res, *rp;
struct sockaddr_storage peer_addr;
socklen_t peer_addr_len;
int sfd, cfd;
if(argc != 3) {
fprintf(stderr, "Usage: %s address port\n", argv[0]);
exit(EXIT_FAILURE);
}
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = 0;
hints.ai_addr = NULL;
hints.ai_next = NULL;
if(getaddrinfo(argv[1], argv[2], &hints, &res) != 0)
handle_error("getaddrinfo");
// Try each socket until we bind
for(rp = res; rp != NULL; rp = rp->ai_next){
sfd = socket(rp->ai_family, rp->ai_socktype, 0);
if(sfd == -1) continue;
if(bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) break;
else close(sfd);
}
freeaddrinfo(res);
if (rp == NULL){
fprintf(stderr, "Could not bind to any socket\n");
exit(EXIT_FAILURE);
}
// Set the TCP socket to listen state
if (listen(sfd, LISTEN_BACKLOG) == -1) handle_error("listen");
for(;;){
// Accept
peer_addr_len = sizeof(struct sockaddr_storage);
cfd = accept(sfd, (struct sockaddr *) &peer_addr, &peer_addr_len);
if (cfd == -1) handle_error("accept");
// Fork
pid_t pid = fork();
if (pid == 0){
//Child code
char buf[BUF_SIZE];
while(1){
ssize_t nread = recv(cfd, buf, BUF_SIZE, 0);
if (nread == 0) {
close(cfd);
exit(EXIT_SUCCESS);
} else {
ssize_t nsent = send(cfd, buf, nread, 0);
if (nsent != nread) fprintf(stderr, "Error sending response");
}
}
} else {
//Parent code
}
}
close(sfd);
}
It compiles just fine, but when I try running it as tcp_server 127.0.0.1 80 it gives me the error message Could not bind to any socket.
In my understanding, this should have bound the server to the IPv4 loopback address, port 80, and then I would have been able to interact with it using netcat.
What is going on?

Low-numbered ports are considered privileged by most operating systems. Try with a port like 8000 or 8080.

Since you are passing port 80 via command line argument i.e. ARGV[2]. The Port No. 80 is the port number assigned to commonly used internet communication protocol, Hypertext Transfer Protocol (HTTP).
You can use the port according to the below classification:
1. Ports 0–1023 – system or well-known ports
2. Ports 1024–49151 – user or registered ports
3. Ports >49151 – dynamic / private ports
So by this might, your problem will get solved.

Related

IPv6 client cannot connect to IPv6 server, cannot assign requested address

Re-using code here to reproduce a tcp client/server interaction.
The server initializes fine, begins listening for connections.
However, on running client ./client, the client fails with message
connect(): Cannot assign requested address
where the "failing" code from the link above (and also pasted below) is:
ret = connect(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
if (ret == -1) {
perror("connect()");
close(sock_fd);
return EXIT_FAILURE;
}
When I run ifconfig, I do not see an IPv6 address. Is this a possible explanation? I am running an Ubuntu Docker image on an OSX machine.
The code is easily compilable/runnable with
gcc server.c -o server
gcc client.c -o client
./server
./client
server.c
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netinet/in.h>
#define CLIENT_QUEUE_LEN 10
#define SERVER_PORT 7002
int main(void)
{
int listen_sock_fd = -1, client_sock_fd = -1;
struct sockaddr_in6 server_addr, client_addr;
socklen_t client_addr_len;
char str_addr[INET6_ADDRSTRLEN];
int ret, flag;
char ch;
/* Create socket for listening (client requests) */
listen_sock_fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if(listen_sock_fd == -1) {
perror("socket()");
return EXIT_FAILURE;
}
/* Set socket to reuse address */
flag = 1;
ret = setsockopt(listen_sock_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
if(ret == -1) {
perror("setsockopt()");
return EXIT_FAILURE;
}
server_addr.sin6_family = AF_INET6;
server_addr.sin6_addr = in6addr_any;
server_addr.sin6_port = htons(SERVER_PORT);
/* Bind address and socket together */
ret = bind(listen_sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
if(ret == -1) {
perror("bind()");
close(listen_sock_fd);
return EXIT_FAILURE;
}
/* Create listening queue (client requests) */
ret = listen(listen_sock_fd, CLIENT_QUEUE_LEN);
if (ret == -1) {
perror("listen()");
close(listen_sock_fd);
return EXIT_FAILURE;
}
client_addr_len = sizeof(client_addr);
while(1) {
/* Do TCP handshake with client */
client_sock_fd = accept(listen_sock_fd,
(struct sockaddr*)&client_addr,
&client_addr_len);
if (client_sock_fd == -1) {
perror("accept()");
close(listen_sock_fd);
return EXIT_FAILURE;
}
inet_ntop(AF_INET6, &(client_addr.sin6_addr),
str_addr, sizeof(str_addr));
printf("New connection from: %s:%d ...\n",
str_addr,
ntohs(client_addr.sin6_port));
/* Wait for data from client */
ret = read(client_sock_fd, &ch, 1);
if (ret == -1) {
perror("read()");
close(client_sock_fd);
continue;
}
/* Do very useful thing with received data :-) */
ch++;
/* Send response to client */
ret = write(client_sock_fd, &ch, 1);
if (ret == -1) {
perror("write()");
close(client_sock_fd);
continue;
}
/* Do TCP teardown */
ret = close(client_sock_fd);
if (ret == -1) {
perror("close()");
client_sock_fd = -1;
}
printf("Connection closed\n");
}
return EXIT_SUCCESS;
}
client.c
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#define SERVER_PORT 7002
int main(int argc, char *argv[])
{
int sock_fd = -1;
struct sockaddr_in6 server_addr;
int ret;
char ch = 'a';
/* Arguments could be used in getaddrinfo() to get e.g. IP of server */
(void)argc;
(void)argv;
/* Create socket for communication with server */
sock_fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (sock_fd == -1) {
perror("socket()");
return EXIT_FAILURE;
}
/* Connect to server running on localhost */
server_addr.sin6_family = AF_INET6;
inet_pton(AF_INET6, "::1", &server_addr.sin6_addr);
server_addr.sin6_port = htons(SERVER_PORT);
/* Try to do TCP handshake with server */
ret = connect(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
if (ret == -1) {
perror("connect()");
close(sock_fd);
return EXIT_FAILURE;
}
/* Send data to server */
ret = write(sock_fd, &ch, 1);
if (ret == -1) {
perror("write");
close(sock_fd);
return EXIT_FAILURE;
}
/* Wait for data from server */
ret = read(sock_fd, &ch, 1);
if (ret == -1) {
perror("read()");
close(sock_fd);
return EXIT_FAILURE;
}
printf("Received %c from server\n", ch);
/* DO TCP teardown */
ret = close(sock_fd);
if (ret == -1) {
perror("close()");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
So when I ran the code on a non docker container (the host) which has an IPv6 address based on running ifconfig, I get the output
Received b from server
which appears to confirm my suspicion that the container does not support IPv6.
If anyone cares to elaborate, they are welcome to.
Your server_addr.sin6_flowspec and other members of that struct are being left uninitialized.
Start by zero'ing out your server_addr instances before passing it to connect.
Either this at declaration time:
struct sockaddr_in6 server_addr = {0};
Or a memset call to fill it with all zeros before you start assigning the members of that struct values.
memset(&server_addr, '\0', sizeof(server_addr));
I believe that will fix your issue. If not, read on.
If the above doesn't resolve your issue, it's likely because you aren't properly initializing the sin6_flowspec or other members of the sockaddr_in6 struct that aren't in the ipv4 sockaddr_in struct. You can leverage getaddrinfo to do the heavy work for you to properly fill in these fields.
int result = 0;
addrinfo* resultList = NULL;
addrinfo hints = {};
hints.ai_family = AF_INET6;
hints.ai_flags |= AI_NUMERICHOST; // comment this line out if getaddrinfo fails
hints.ai_socktype = SOCK_STREAM;
int result = getaddrinfo("::1", NULL, &hints, &resultList);
if ((result == 0) && (resultList->ai_family == AF_INET6))
{
memcpy(&server_addr, resultList->ai_addr, sizeof(sockaddr_in6));
server_addr.sin6_port = htons(SERVER_PORT);
}
else
{
// fail
}
if (resultList)
{
freeaddrinfo(&resultList);
}
resultList = NULL;

The UDP sendto() and recvfrom() functions are not working as expected

I wanted to implement a simple UDP server and client, so I wrote the code halfway in C language.
The purpose of the code is to send a message from the Client to the Server, and if the message is sent correctly, the Server sends an "ACK" message to the Client.
However, the return values of sendto() and recvfrom() are -1, and the message is not sent.
In udpserver.c, I know that "ACK" is firmly overwritten in buf by strcpy.
In udpserver.c, I can send messages and in udpclient.c, I can receive messages, but I don't know how to write code from here. Can you give me some specific code?
Also, I want the server to say Hello, and the client to say ACK.
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define MYPORT "4567" // the port that client will be connecting to
#define MAXBUFLEN 100
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
int sockfd;
struct addrinfo hints, *servinfo, *p;
int rv;
int numbytes;
struct sockaddr_storage their_addr;
char buf[MAXBUFLEN];
int32_t receivedNumber;
socklen_t addr_len;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
hints.ai_socktype = SOCK_DGRAM; // UDP
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("server: socket");
continue;
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "listener: failed to bind socket\n");
exit(1);
}
printf("server: waiting for client...\n");
addr_len = sizeof their_addr;
//Receive from client
if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1 , 0, (struct sockaddr *)&their_addr, &addr_len)) == -1) {
perror("recvfrom");
exit(1);
}
printf("Received from client: %s\n", buf);
strcpy(buf,"ACK");
//Send client an ACK message
if(sendto(sockfd,buf,strlen(buf),0,p->ai_addr,p->ai_addrlen)==-1){
printf("Error\n");
}
/*
unknown code
*/
freeaddrinfo(servinfo);
close(sockfd);
return 0;
}
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define SERVERPORT "4567" // the port that client will be connecting to
#define MAXBUFLEN 100
int main(int argc, char *argv[])
{
int sockfd;
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr;
socklen_t addr_len;
int rv;
int numbytes;
char buf[MAXBUFLEN];
if (argc != 3) {
fprintf(stderr,"usage: talker hostname message\n");
exit(1);
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
if ((rv = getaddrinfo(argv[1], SERVERPORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and make a socket
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("talker: socket");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "talker: failed to create socket\n");
return 2;
}
// Send to server
if ((numbytes = sendto(sockfd, argv[2], strlen(argv[2]), 0, p->ai_addr, p->ai_addrlen)) == -1) {
perror("client: sendto");
exit(1);
}
//Receive from server
if(recvfrom(sockfd,buf,MAXBUFLEN-1,0,(struct sockaddr *)&their_addr,&p->ai_addrlen)==-1){
printf("Error\n");
}
/*
unknown code
*/
printf("Received from server: %s\n", buf);
freeaddrinfo(servinfo);
close(sockfd);
return 0;
}
gcc udpserver.c
./a.out
server: waiting for client...
Received from client: Hello~
gcc udpclient.c
./a.out 127.0.0.1 Hello
Received from server: �*��z ```
If you read from a channel into a buffer and the result is positive, then you have successfully read some bytes, but not a null-terminated string.
e.g.
numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1, ...);
numbytes is the number of bytes read, now it is time to make a string:
buf[numbytes] = '\0';
Both the client and server do not add the null-byte to the end of buf.

TCP client/server in c

I created a TCP client/server and was provided test script, however, beyond short messages, all tests are failing. Simply, the script send arbitrary messages that the client reads through redirection from a file to ther server. However with randomly created files by the script, it says that the messages on receving/sending side do not match. Any help will be appreciated, below is the client and server code.
// server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>
#define QUEUE_LENGTH 10
#define RECV_BUFFER_SIZE 2048
/* TODO: server()
* Open socket and wait for client to connect
* Print received message to stdout
* Return 0 on success, non-zero on failure
*/
int server(char *server_port) {
int sockfd, new_fd;
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; // connector's address
socklen_t sin_size;
int yes = 1;
char s[INET6_ADDRSTRLEN];
int rv;
char buff[RECV_BUFFER_SIZE];
int numBytes;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my ip address
if ((rv = getaddrinfo(NULL, server_port, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("server: socket");
continue;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind");
continue;
}
break;
}
freeaddrinfo(servinfo); // all done with this structure
if (p == NULL) {
fprintf(stderr, "server: failed to bind\n");
exit(1);
}
if (listen(sockfd, QUEUE_LENGTH) == -1) {
perror("listen");
exit(1);
}
// printf("server: waiting for connections...\n");
while (1) {
sin_size = sizeof their_addr;
if((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
perror("accept");
continue;
}
if (!fork()) { // child process
close(sockfd); // child does not need the listener
if ((numBytes = recv(new_fd, buff, RECV_BUFFER_SIZE -1, 0)) == -1) {
perror("recv");
exit(1);
}
buff[numBytes] = '\0';
printf("%s", buff);
close(new_fd);
exit(0);
}
close(new_fd);
}
return 0;
}
/*
* main():
* Parse command-line arguments and call server function
*/
int main(int argc, char **argv) {
char *server_port;
if (argc != 2) {
fprintf(stderr, "Usage: ./server-c [server port]\n");
exit(EXIT_FAILURE);
}
server_port = argv[1];
return server(server_port);
}
// client.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>
#define SEND_BUFFER_SIZE 2048
/* TODO: client()
* Open socket and send message from stdin.
* Return 0 on success, non-zero on failure
*/
int client(char *server_ip, char *server_port)
{
int sockfd;
int status;
struct addrinfo hints, *servinfo, *p;
char send_buff[SEND_BUFFER_SIZE];
int numbytes;
char s[INET6_ADDRSTRLEN];
// getaddrinfo
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((status = getaddrinfo(server_ip, server_port, &hints, &servinfo)) != 0)
{
fprintf(stderr, "getadrrinfo: %s\n", gai_strerror(status));
return 1;
}
for (p = servinfo; p != NULL; p = p->ai_next)
{
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1)
{
perror("client: socket");
continue;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("client: socket");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "client: failed to connect\n");
return 2;
}
freeaddrinfo(servinfo);
// reading from stdin into send_buff, then send
if((numbytes = read(0, send_buff, SEND_BUFFER_SIZE)) != -1) {
if (send(sockfd, send_buff, numbytes, 0) == -1) {
perror("send");
exit(1);
}
}
close(sockfd);
return 0;
}
/*
* main()
* Parse command-line arguments and call client function
*/
int main(int argc, char **argv)
{
char *server_ip;
char *server_port;
if (argc != 3)
{
fprintf(stderr, "Usage: ./client-c [server IP] [server port] < [message]\n");
exit(EXIT_FAILURE);
}
server_ip = argv[1];
server_port = argv[2];
return client(server_ip, server_port);
}
2048 bytes exceed in size the typical MTU (note that TCP is laid over IP, which itself is packet oriented), so data is likely sent via multiple packets. As you have only one single call to recv chances are that you fetch the contents of first packet from the receive buffer before the the TCP/IP stack could place the contents of the follow up packets there.
Rather have multiple reads in a loop and exit the loop on receiving 0 bytes (remote socket closed):
while((numBytes = recv(new_fd, buff, RECV_BUFFER_SIZE -1, 0)) > 0)
{
buff[numBytes] = '\0';
printf("%s", buff);
}
if(numBytes < 0)
{
// error handling
}

Unbinding ports

I launched a process from terminal that bound some ports.
The code in questions is this one:
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#define BUF_SIZE 500
#define LISTEN_BACKLOG 50
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int
main(int argc, char *argv[])
{
struct addrinfo hints;
struct addrinfo *res, *rp;
struct sockaddr_storage peer_addr;
socklen_t peer_addr_len;
int sfd, cfd;
if(argc != 3) {
fprintf(stderr, "Usage: %s address port\n", argv[0]);
exit(EXIT_FAILURE);
}
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = 0;
hints.ai_addr = NULL;
hints.ai_next = NULL;
if(getaddrinfo(argv[1], argv[2], &hints, &res) != 0)
handle_error("getaddrinfo");
// Try each socket until we bind
for(rp = res; rp != NULL; rp = rp->ai_next){
sfd = socket(rp->ai_family, rp->ai_socktype, 0);
if(sfd == -1) continue;
if(bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) break;
else close(sfd);
}
freeaddrinfo(res);
if (rp == NULL){
fprintf(stderr, "Could not bind to any socket\n");
exit(EXIT_FAILURE);
}
// Set the TCP socket to listen state
if (listen(sfd, LISTEN_BACKLOG) == -1) handle_error("listen");
printf("Server started");
for(;;){
// Accept
peer_addr_len = sizeof(struct sockaddr_storage);
cfd = accept(sfd, (struct sockaddr *) &peer_addr, &peer_addr_len);
if (cfd == -1) handle_error("accept");
// Fork
pid_t pid = fork();
if (pid == 0){ //Child code
pid_t my_pid = getpid();
char buf[BUF_SIZE];
while(1){
ssize_t nread = recv(cfd, buf, BUF_SIZE, 0);
if (nread == 0) {
close(cfd);
exit(EXIT_SUCCESS);
} else {
buf[nread] = 0;
fprintf(stdout, "Worker %i has received a message: %s", my_pid, buf);
ssize_t nsent = send(cfd, buf, nread, 0);
if (nsent != nread) fprintf(stderr, "Error sending response");
}
}
}
close(sfd);
}
After invoking the code I killed the process, and noticed that I could not run the program twice using the same port.
I checked sudo lsof -i -P -n | grep LISTEN and it listed the ports I had used for testing as being in LISTEN state and my program being the culprit for that.
How can I unbind the ports? How do I modify my code so it unbinds the ports itself after receiving a suitable signal?

How does an incoming connection stop select from waiting?

As in the example, select monitors the socket of the server that listens for an incoming connection. I used telnet to test the program. In the program, select is supposed to stop waiting when there is something to read from the listener socket. I guessed telnet may send a message to the server and tried to read it, but I got nothing. Actually, the program stopped accepting new connections when I tried to read the message from telnet. I commented out the message reading code. Can someone explain why select stops waiting when there is a new connection?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include "../cus_header/cus_header.h"
#define PORT "30000" // the port users will be connecting to
#define MY_IP "127.0.0.1"
#define BACKLOG 10 // how many pending connections queue will hold
#define MAXLEN 1000
void *get_client_addr(struct sockaddr * sa){
if(sa->sa_family == AF_INET){
return &(((struct sockaddr_in *)(sa))->sin_addr);
}
return &(((struct sockaddr_in6 *)(sa))->sin6_addr);
}
int main(int argc, char *argv[]){
struct addrinfo hints, *res, *p;
struct sockaddr_storage client_addr;
int client_add_len;
char client_ip[INET6_ADDRSTRLEN];
int a;
int listener, new_fd;
int yes = 1;
socklen_t c_addr_size;
char msg [] = "Hello client\n"; // message to the client
char *msg_p;
int msg_len = strlen(msg);
// load data to struct addrinfo
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
//create socket
if((a = getaddrinfo(MY_IP, PORT, &hints, &res)) == -1){
fprintf(stderr, "Cannot get address info: %s", gai_strerror(a));
return 1;
}
p = res;
// loop through all the results
for(p = res; p != NULL; p = p->ai_next){
// create socket
if((listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
printf("cannot create the socket\n");
continue;
}
if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){
error("cannot set reused for the socket");
}
// bind socket to port
if(bind(listener, p->ai_addr, p->ai_addrlen) == -1){
printf("cannot bind the socket\n");
continue;
}
break;
}
if(p == NULL){
error("Cannot create socket or bind the socket to the port");
}
freeaddrinfo(res);
// listen incoming connections
if(listen(listener, BACKLOG) == -1){
error("Cannot listen to connection");
}
// ready to communicate
puts("Waiting for connection ...");
fd_set master_set, copy_master_set;
int fd_max;
int client_fd[20]; // store all the new fd here
// accept connection and talk with clients
while(1){
FD_ZERO(&master_set);
FD_SET(listener, &master_set);
fd_max = listener;
copy_master_set = master_set;
if(select(fd_max + 1, &copy_master_set, NULL, NULL, NULL) == -1){
error("Select");
}
int i;
// set all the available client fd
for(i = 0;i <= fd_max; i++){
if(FD_ISSET(i, &copy_master_set)){
if(i == listener){
// got a new connection
client_add_len = sizeof client_addr;
if((new_fd = accept(listener, (struct sockaddr *)&client_addr, &client_add_len)) == -1){
error("New connection");
}
FD_SET(new_fd, &master_set);
if(new_fd > fd_max){
fd_max = new_fd;
}
printf("New connection from %s on socket %i\n",
inet_ntop(client_addr.ss_family, get_client_addr((struct sockaddr *)&client_addr), client_ip, INET6_ADDRSTRLEN),
new_fd);
/*
char buf[MAXLEN];
int b;
if((b=recv(listener, buf, MAXLEN, 0)) == -1){
error("read message");
}else if(b == 0){
printf("Message from client: %s", buf);
}
printf("Message from client: %s", buf);
*/
}else{
// handle clients
}
}
}
}
return 0;
}
From the man page for select:
DESCRIPTION
select() and pselect() allow a program to monitor multiple file
descriptors, waiting until one or more of the file descriptors
become "ready" for some class of I/O operation (e.g., input
possible). A file descriptor is considered ready if it is pos-
sible to perform the corresponding I/O operation (e.g.,
read(2)) without blocking.
In this case, the file descriptor becomes ready when the socket receives an incoming connection and it is possible to perform the corresponding I/O operation of accept(2).

Resources