0

I'm new in socket programming. I'm trying to make simple client, server program where the message sent from client appears on the server window. However it works for only one client. How to handle multiple clients. Thanks in advance. Here's my code
Server.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>

#define ERROR -1
#define MAX_DATA 1024

int main(){
  int welcomeSocket, newSocket;
  char buffer[MAX_DATA];
  int data_len;
  struct sockaddr_in serverAddr;
  int addr_size = sizeof(struct sockaddr_in);

  if((welcomeSocket = socket(PF_INET, SOCK_STREAM, 0)) == ERROR){
    printf("Socket: ");
    exit(-1);
  }
  /* Configure settings of the server address struct */
  serverAddr.sin_family = AF_INET;
  serverAddr.sin_port = htons(9999);
  serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
  /* Set all bits of the padding field to 0 */
  memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);  

  /* Bind the server address struct to the socket */
  bind(welcomeSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));

  /* Listen on the socket, with 5 max connection requests queued */
  if(listen(welcomeSocket,5) == 0)
    printf("Listening\n");
  else
    printf("Error\n");

  while(1){
    /* Accept call for the incoming connection */
    if((newSocket = accept(welcomeSocket, (struct sockaddr *)&newSocket, &addr_size)) == ERROR){
      perror("accept");
      exit(-1);
    }
    data_len = 1;
    while(data_len){
      /* receive msg and print */
      data_len = recv(newSocket, buffer, MAX_DATA, 0);
      if(data_len){
        buffer[data_len] = '\0';
        printf("%s\n", buffer);
      }
    }
  }
  printf("Client Disconnected\n");
  close(newSocket);

  return 0;
}
pratap
  • 23
  • 1
  • 8
  • 2
    A classic and standard approach is `select()` or `poll()`. For high load, you need platform-dependent alternatives (like e.g. Linux' `epoll()`) or a library abstracting them like `libevent`. As a question, this is too broad, sorry. –  Aug 02 '17 at 10:09
  • Possible duplicate of [C, socket programming: Connecting multiple clients to server using select()](https://stackoverflow.com/questions/4200172/c-socket-programming-connecting-multiple-clients-to-server-using-select) – Adit Ya Aug 02 '17 at 10:17
  • Note, from 'man recv()': 'These calls return the number of bytes received, or -1 if an error occurred'. So, this 'buffer[data_len] = '\0'' would then be UB from an underflow write, (-1 not being false) ;( – Martin James Aug 02 '17 at 10:26
  • @MartinJames that operation will be performed only if some data is received. I'm checking the condition just above it.. see – pratap Aug 02 '17 at 10:28
  • @pratap 'that operation will be performed only if some data is received.' no, it won't:( recv() can also return on an error, and will return '-1' which, not being 0, (ie. not false), the 'if' test will pass and the out-of-bounds write will occur: UB;( – Martin James Aug 02 '17 at 10:37

2 Answers2

2

There are a couple of strategies to handle multiple clinets on server. First is to use threading which means a new thread is assigned to each new client and handles all its traffics. This way main thread is not blocked by read/write or rec/send system calls and is free to handle new incomming clients. Second strategy is to use Non blocking I/O which is a little harder than the first strategy but it is quite good in both performance and resource consumption. Third strategy is to use a unique port number for each client, some commercial programs use this strategy but I do not personnaly advise towards it. If I were to write a server application, which I have done more than that could be counted, I would have chosen non blocking I/O, although it's a little hard to get it to work for first few tries, but it is quite worth it and work in any way better than all other strategies. Search for nonblocking I/O and select() for furthur instructions

HRN
  • 21
  • 4
0

You can use multithreading to manage multiple clients at one time, so the server can listen "at the same time" new connections while waiting for each client messages to be received.

When your server call accept(), if no client is joining, the call will "block" the execution until someone is joining.

Then, for the same reason, the call of recv() will block the main thread until a client has sent a message.

Using multithreading will cause the blocking of recv() and accept() won't affect the main thread.

Cid
  • 14,968
  • 4
  • 30
  • 45
  • While this could work, it's not a necessity to use threads and event-based implementations are often preferred. I don't think such a hint qualifies as an *answer*, it should better be a comment. –  Aug 02 '17 at 10:12
  • I can't yet post comments, I joined StackOverflow yesterday. – Cid Aug 02 '17 at 10:15
  • 1
    That's not a good reason to post as an answer instead. Try to find some questions that allow for a direct and complete answer and answer these, and you will have enough reputation to write comments very quickly. –  Aug 02 '17 at 10:17
  • @FelixPalmen He is certainly mistaken to use the word 'need'. He should either have said 'can' or mentioned non-blocking multiplexed I/O, and also asynchronous I/O, which I don't see in your comments anywhere as a third solution. However this answer is certainly much more than a comment, and there is certainly 'could work' about it: it *will* work. – user207421 Aug 02 '17 at 10:22
  • 1
    @EJP indeed, I should have been more precise and used 'can' rather than 'need'. I'll made some edit about it – Cid Aug 02 '17 at 10:28
  • @EJP it *will* work depending on the scenario. With moderate work, any of the three alternatives you mention will work, of course. It's more like an answer in the current state, but the original version really wasn't more than a hint. As I read the help pages here, something just "*pointing into the right direction*" indeed *can* be an answer, it's probably not a good one without explanations. –  Aug 02 '17 at 11:00
  • @FelixPalmen I am unable to understand you. Starting a new thread per connection is what about 90% of the TCP servers on the planet already do. It will work when executed correctly. There is, and was, nothing comment-like about this answer whatsoever. – user207421 Aug 02 '17 at 11:12
  • The aren't that much different anyway, for many purposes. Thread-per-connection, and the state-machine for handling multiple clients and calls that may block is supported by the kernel. Select/poll, and the the state-machine for handling multiple clients must be provided by user code, as should an async strategy for avoiding blocking calls. Pick your poison... – Martin James Aug 02 '17 at 11:23
  • @EJP This is a *hint* in *one possible* direction just throwing in the name of a technique, and, in it's original one-sentence form, didn't explain anything about it. Depending on how you read the site rules, it could be considered a partial answer, but something like this is always better posted as a comment. –  Aug 02 '17 at 11:30
  • @FelixPalmen That stance would eliminate 90% of answers on this topic. It's an extremely well-known solution. It doesn't need elaborating every time it is mentioned. – user207421 Aug 03 '17 at 03:27
  • @EJP which is a clear sign the question itself is too broad. There **are** a lot of possible answers, and I don't agree: **all** of them should be explained when mentioned in an answer. –  Aug 03 '17 at 05:14