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, ©_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, ©_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).
Related
I'm trying to launch multiple servers, at once, in a c program. For the sake of simplicity let's say 5 servers.
If I understand well the sockets, each of them must be listening to a different IP socket address (different PORT, different IP interface address).
I thought to do that inside a loop, incrementing port number by i at each turn. Here's my current code just to launch one server. I know it's possible with bash by launching the same process in background, but in C I really don't know how to do that and if it's even possible
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
long PORT;
int main(int argc, char const *argv[])
{
/* 1. Open a socket
2. Bind to a address(and port).
3. Listen for incoming connections.
4. Accept connections
5. Read/Send
*/
int listenerSocket; /* socket for accepting connections */
int clientSocket; /* socket connected to client */
struct sockaddr_in server;
struct sockaddr_in client; /* client address information */
char buf[100]; /* buffer for sending & receiving data */
int errnum;
listenerSocket = socket(AF_INET, SOCK_STREAM, 0);
if(listenerSocket == -1){
perror("erreur lors de la création du socket");
}
PORT = strtol(argv[1], NULL, 10);
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port= htons(PORT);
if (bind(listenerSocket, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
puts("Server waiting for connection...");
while(1){
if (listen(listenerSocket, 5) < 0){
perror("listen failed");
exit(EXIT_FAILURE);
}
int c = sizeof(client);
if((clientSocket = accept(listenerSocket, (struct sockaddr*) &client, &c)) < 0){
puts("error accepting the request");
perror("Accept()");
}
puts("connection accepted");
while(1){
if( recv(clientSocket, buf, sizeof(buf), 0) < 0) {
errnum = errno;
perror("Recv()");
printf("val printed by errno: %d\n",errno);
}
printf("Message : %s\n", buf);
}
if (send(clientSocket, buf, sizeof(buf), 0) < 0)
{
perror("Send()");
exit(7);
}
close(clientSocket);
close(listenerSocket);
printf("Server ended successfully\n");
exit(0);
}
I created a client/server chatroom in C. I need to put in a global table of all clients connected so that I can send every message the server receives to all the clients connected. I can't figure out how to do this. I assume I have to create a struct of some sort and add every specific socket descriptor for each thread I spawn. Then I have to send my message to every specific SD in that struct.
I don't know how to code this and wanted to see if anyone could show me some example code of what I have to write after every connection is made and what I have to write to then send my messages to every thread. My server code is below if needed.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <malloc.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <errno.h>
#include <netdb.h>
#include <sys/stat.h>
#include <fcntl.h>
void *
client_session_thread(void * arg)
{
int SD;
char request[2048];
char message[2048] = "server receives input: ";
int chatfile;
char msgr[50000];
SD = *(int *)arg;
free (arg);
pthread_detach(pthread_self());
chatfile = open("chathistory.txt", O_RDWR|O_CREAT|O_EXCL,0666);
close(chatfile);
chatfile = open("chathistory.txt", O_RDWR | O_APPEND);
read(chatfile,msgr,sizeof(msgr));
write(SD, msgr, strlen(msgr));
while (read(SD, request, sizeof(request)))
{
strcat(message, request);
strcat(message,"\n");
fprintf(stdout, message);
write(SD,request,strlen(request));
write(chatfile,request,strlen(request));
strcpy(request,"");
strcpy(message, "server receives input: ");
bzero(request, sizeof(request));
bzero(message,sizeof(message));
}
close(SD);
close(chatfile);
return 0;
}
int main(int argc, char *argv[])
{
//create a socket. SD is my socket.
struct addrinfo addrinfo;
struct addrinfo * result;
char message[256];
int SD;
int FD;
pthread_t ignore;
int * FDpntr;
int on = 1;
addrinfo.ai_flags = 0;
addrinfo.ai_family = AF_INET; // IPv4 only
addrinfo.ai_socktype = SOCK_STREAM; // Want TCP/IP
addrinfo.ai_protocol = 0; // Any protocol
addrinfo.ai_addrlen = 0;
addrinfo.ai_addr = NULL;
addrinfo.ai_canonname = NULL;
addrinfo.ai_next = NULL;
if (getaddrinfo("clamshell.rutgers.edu", "5700", &addrinfo, &result) !=0)
{
printf("\x1b[1;31mProblem with getaddrinfo\x1b[0m\n");
}
//Create socket
SD = socket(AF_INET, SOCK_STREAM, 0);
if (SD == -1)
{
printf("\x1b[1;31mProblem creating socket\x1b[0m\n");
}
//Bind the socket to our specified IP and port
if (setsockopt(SD, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) ==-1)
{
printf("\x1b[1;31mProblem with sockopt\x1b[0m\n");
freeaddrinfo(result);
return -1;
}
if (bind(SD, result->ai_addr, result->ai_addrlen) != 0)
{
printf("\x1b[1;31mProblem binding socket\x1b[0m\n");
}
//first we bind our socket and then recast our address just like in client
//Listen function listens for connections
if (listen(SD, 20) == -1)
{
printf("\x1b[1;31mProblem with listen\x1b[0m\n");
close(SD);
return 0;
}
else
{
//Accept function for accepting incoming connection
//sos = sizeof(struct sockaddr_in);
//while (FD = accept(SD, (struct sockaddr *)&client, (socklen_t*)&sos))
while ((FD = accept(SD,0,0)) != -1)
{
FDpntr = (int *)malloc(sizeof(int));
*FDpntr = FD;
if (pthread_create(&ignore, NULL, client_session_thread, FDpntr) != 0)
{
printf("\x1b[1;31mProblem creating thread\x1b[0m\n");
}
else
{
continue;
}
}
close(SD);
return 0;
}
}
suggest implement a separate file.
That file would have entry points:
initializeClientTable()
destroyClientTable()
addClient()
deleteClient(),
getClient()
The getClient() function would return a client.
it would have a parameter that (probably an enum value) that indicates to get the first client or get the next client from the ClientTable
When at the end of the ClientTable, return an indication of such event.
The ClientTable could easily be implemented as a linked list.
My socket server program is mentioned below. It works fine with the single client but when I try to connect it with another client at the same time, I am unable to connect. But I have defined MAX_CLIENTS in my program as 2 but still why I am unable to connect with multiple clients? What is the correct process to connect with multiple client? Will I be able to connect with multiple client by modifying this code? Any possible fix?
Socket Server Code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <error.h>
#include <strings.h>
#include <unistd.h>
#include <arpa/inet.h>
#define ERROR -1
#define MAX_CLIENTS 2
#define MAX_DATA 1024
main (int argc, char **argv){
struct sockaddr_in server;
struct sockaddr_in client;
int sock;
int new;
int sockaddr_len = sizeof (struct sockaddr_in);
int data_len;
char data [MAX_DATA];
if ((sock = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
perror ("socket: ");
exit (-1);
}
printf("after socket");
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));
server.sin_addr.s_addr = INADDR_ANY;
bzero (&server.sin_zero, 8);
printf("after server");
if ((bind (sock, (struct sockaddr*)&server, sockaddr_len)) == -1)
{
perror ("bind");
exit (-1);
}
printf("after bind");
if ((listen(sock, MAX_CLIENTS)) == ERROR)
{
perror ("listen");
exit (-1);
}
printf("after listen");
while(1)
{
if ((new = accept(sock, (struct sockaddr*)&client, &sockaddr_len)) == ERROR)
{
perror ("accept");
exit (-1);
}
printf("after new");
printf("New client connected from port no %d and IP %s\n",ntohs(client.sin_port), inet_ntoa(client.sin_addr));
data_len = 1;
while (data_len)
{
data_len = recv (new, data, MAX_DATA, 0);
if (data_len)
{
send (new, data, data_len, 0) ;
data [data_len]='\0';
printf("Sent mesg: %s", data);
}
printf("after datalen");
}
printf("Client Disconnected\n");
close(new);
}
printf("after close new");
close (sock);
}
Your program is single-threaded, and only does one thing at a time. When you have accepted a socket connection from a client (in your outer while loop) you start communicating with that client (in your inner while loop), and you don't get back to the accept call until the first client has disconnected.
Either use threads, with one thread that waits for new connections and one additional thread for each client, waiting for input from that client, or use the select call, which lets you wait for input simultaneously from several different sources.
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <winsock.h>
#pragma once
#pragma comment (lib, "ws2_32.lib")
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <winsock.h>
#include <io.h>
SOCKET sock;
SOCKET fd;
char recv_data[10];
int port = 18001;
void CreateSocket()
{
struct sockaddr_in server, client; // creating a socket address structure: structure contains ip address and port number
printf("Initializing Winsock\n");
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD (1, 1);
if (WSAStartup (wVersionRequested, &wsaData) != 0){
printf("Winsock initialised failed \n");
} else {
printf("Initialised\n");
}
// create socket
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0) {
printf("Could not Create Socket\n");
//return 0;
}
printf("Socket Created\n");
// create socket address of the server
memset( &server, 0, sizeof(server));
// IPv4 - connection
server.sin_family = AF_INET;
// accept connections from any ip adress
server.sin_addr.s_addr = htonl(INADDR_ANY);
// set port
server.sin_port = htons(port);
//Binding between the socket and ip address
if(bind (sock, (struct sockaddr *) &server, sizeof(server)) < 0)
{
printf("Bind failed with error code: %d", WSAGetLastError());
}
//Listen to incoming connections
if(listen(sock,3) == -1){
printf("Listen failed with error code: %d", WSAGetLastError());
}
printf("Server has been successfully set up - Waiting for incoming connections");
int len;
len = sizeof(client);
fd = accept(sock, (struct sockaddr*) &client, &len);
if (fd < 0){
printf("Accept failed");
}
//echo(fd);
printf("\n Process incoming connection from (%s , %d)", inet_ntoa(client.sin_addr),ntohs(client.sin_port));
//closesocket(fd);
}
int main()
{
CreateSocket();
while(1)
{
if(fd == -1)
{
printf("socket error\n");
}
else
{
recv(fd, recv_data, 9, 0);
printf("value is %s", recv_data);
}
}
return 0;
}
The above is a server code : I am creating a socket and accepting the data from the client. The client is sending a data and the server is accepting it.
If the client sends a to the server then the server will add some junk characters to it. If the client sends 4 characters then it will receive all the four characters. if the client sends one or two characters :Why the server is receiving some junk value ??
This is because, recv does not append NULL character at the end of the string. You have to explicitly add the NULL character. So, use return value of recv call and use it to append the NULL character.
int retval;
retval = recv(fd, recv_data, 9, 0);
if(retval != SOCKET_ERROR) {
recv_data[retval] = '\0';
printf("value is %s", recv_data);
}
'\0' is the only character which will differ you from char array and string.
Since you are using %s to print the string it is necessary to add the '\0' character at the end.
I'm new to network programming. I have to write a simple client/server program in C. The server will listen for a connection and the client will connect to the server, send a message, and receive an echo back from the client. We have to update this using select() to handle connections to multiple clients at the same time from the server process. I tried to implement select() on the client side like instructed,but I think I'm having an infinite loop on the client side in if(FD_ISSET(clientSockfd, &readfds)) part.
//client1.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <resolv.h>
#include <arpa/inet.h>
const int BUF_SIZE = 512;
int main(int argc, char *argv[]) {
char buf[BUF_SIZE], buf2[BUF_SIZE];
char *msg;
struct sockaddr_in serverInfo;
int clientSockfd, errorCheck, readVal, numfd;
struct hostent *hostName;
fd_set readfds;
//make sure user entered correct arguments when starting client
if(argc != 3)
{
printf("error: must enter 'programName portNumber hostname'\n");
exit(errno);
}
//create socket and error check socket() call
clientSockfd=socket(AF_INET, SOCK_STREAM, 0);
if (clientSockfd == -1)
{
perror("error creating socket");
exit(errno);
}
//assign sockaddr_in info for RemoteAddr
bzero(&serverInfo, sizeof(serverInfo));
serverInfo.sin_family=AF_INET;
hostName=gethostbyname(argv[2]);
if(hostName == NULL)
{
herror("Error when calling gethostbyname()");
exit(errno);
}
memcpy((unsigned char *) &serverInfo.sin_addr, (unsigned char *)hostName->h_addr, hostName->h_length); //copy IP address to be used
serverInfo.sin_port=htons(atoi(argv[1])); //port number to be used, given in command line, must be converted to network byte order
//connect to server side
if(connect(clientSockfd, (struct sockaddr *)&serverInfo, sizeof(serverInfo)) == -1)
{
perror("error when connecting to server");
exit(errno);
}
while(1)
{
FD_ZERO(&readfds); //zero out set
FD_SET(fileno(stdin), &readfds);
FD_SET(clientSockfd, &readfds);
int maxfd = fileno(stdin);
if(maxfd < clientSockfd) maxfd = clientSockfd;
numfd = select(maxfd, &readfds, 0, 0, 0); //call select()
if(numfd > 0)
{
if(FD_ISSET(clientSockfd, &readfds))
{
//make sure buf is empty so it doesnt print extra chars
bzero(buf2, BUF_SIZE);
read(clientSockfd, buf2, BUF_SIZE);
}
if(FD_ISSET(fileno(stdin), &readfds))
{
bzero(buf, BUF_SIZE);
fgets(buf, BUF_SIZE-1, stdin);
printf("echo from server: %s\n", buf);
errorCheck = write(clientSockfd, buf, strlen(buf)+1);
if(errorCheck == -1)
{
perror("error writing");
}
}
}
else if(numfd == 0)
{
perror("Error using select()\n");
exit(0);
}
else
printf("no data\n");
}
//close connection to server
errorCheck = close(clientSockfd);
if(errorCheck == -1)
{
perror("Error closing connection.");
exit(errno);
}
return 0;
}
here is the server..
//server.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <errno.h>
const int ASSIGNED_PORT = 17000;
const int BUF_SIZE = 512;
int main() {
int serverfd, clientfd;
struct sockaddr_in serverSock; //NOTE: a pointer to sockaddr_in can be cast to a pointer to
// a struct sockaddr - useful for connect()
char buf[BUF_SIZE];
int errorCheck, msgLength;
//create socket with error checking (-1 ret on error)
serverfd = socket(AF_INET, SOCK_STREAM, 0);
if(serverfd < 0 )
{
perror("socket failed.");
exit(errno);
}
//assign sockaddr_in info for server
bzero(&serverSock, sizeof(serverSock)); //set to all 0's
serverSock.sin_family = AF_INET;
serverSock.sin_addr.s_addr = htonl(INADDR_ANY);
serverSock.sin_port = htons(ASSIGNED_PORT);
//bind a name to the socket with error checking (0 ret on success)
errorCheck = bind(serverfd, (struct sockaddr*)&serverSock, sizeof(serverSock));
if(errorCheck < 0 )
{
perror("bind failed.");
exit(errno);
}
//listen for connections with error checking (0 ret on success)
errorCheck = listen(serverfd, 10);
if(errorCheck < 0 )
{
perror("listen failed.");
exit(errno);
}
printf("Listening for connections. Enter CNTRL-c to kill server.\n");
//create infinite loop to accept, read, write, and close connections with error hecking
while(1)
{
//accept the connection from the client
clientfd = accept(serverfd, 0, 0);
if(clientfd == -1)
{
perror("error accepting connection.");
exit(errno);
}
//read data from the client
bzero(buf, BUF_SIZE);
msgLength = read(clientfd, buf, BUF_SIZE-1);
if(msgLength == -1)
{
perror("error reading from client");
close(clientfd);
close(serverfd);
exit(errno);
}
if(buf[0] '\0')
{
printf("connection closing");
exit(0);
}
//print what the client sent
printf("Message from client: %s\n", buf);
//echo back what the client sent
errorCheck = write(clientfd, buf, strlen(buf)+1);
if(errorCheck == -1 )
{
perror("error writing to client");
exit(errno);
}
//close the connection
errorCheck = close(clientfd);
if(errorCheck == -1)
{
perror("error closing connection");
exit(errno);
}
}
errorCheck = close(serverfd);
if(errorCheck==-1)
{
perror("error closing server, exiting program now");
sleep(6);
exit(errno);
}
return 0;
}
I think the problem (or at least, a problem) in your client-side code is that you are passing the magic number 32 to select(). That's incorrect. What you should be passing is the maximum of all of the socket numbers, plus one. For example, something like this:
int maxfd = fileno(stdin);
if (maxfd < clientSockFD) maxfd = clientSockFD;
// further maximizations for other sockets would go here, if you had any other sockets...
numfd = select(maxfd+1, &readfds, 0, 0, 0);
You need to use select() on the server side to handle multiple clients, not on the client side.