Strange program behaviour after closing a Linux socket
NickName:a small orange Ask DateTime:2012-11-14T18:45:43

Strange program behaviour after closing a Linux socket

I'm studying Linux/UNIX sockets, so I wrote a very simple "game" based on it, called "21 matches". There's a heap that consists of 21 matches, and each player takes one, two or three matches from it. The person who takes the last match loses the game.

Obviously, the key to winning is to complement your opponent's turn up to 4 matches, so he has to take the very last match (works only if you do the first turn). So, client connects to the server and "plays" against the server till he loses. There can be more than one client connected, so I limit the number of connection, making my host reject any further ones.

The only thing I can't fix or explain is that when someone's getting rejected, the very first client loses the game immediately, even if he hasn't made any turns. This might be explained if I let the new client touch any client's heap, but I don't! I also tracked the buffer array, but it doesn't get harmed in any way.

Here's the code:

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

void die (const char *s, int errcode);
int mkservsock();
void acceptclient();
void dropclient (int client);
void make_turn (int client);

enum
{
  port   = 3333,
  buf_s  = 100,
  limit  = 3
};

void die (const char *s, int errcode)
{
  perror (s);
  exit (errcode);
}

struct pollfd fds[limit + 1];  // client socket descriptors array
int left[limit + 1];           // how many matches left
int nfd = 1;                   // number of the next client
char buffer[buf_s];            // buffer for communicating

// creates a single socket to poll
int mkservsock()
{
  int s = socket (AF_INET, SOCK_STREAM, 0);
  struct sockaddr_in addr;
  addr.sin_family = AF_INET;
  addr.sin_port = htons (port);
  addr.sin_addr.s_addr = INADDR_ANY;
  if (bind (s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
    die ("Can't bind socket", 1);

  if (listen (s, 1) == -1)
    die ("Can't start listening", 1);

  return s;
}

// adds new client to descriptors array or rejects it, if number of connections exceeds the limit
void acceptclient()
{
  int c = accept (fds[0].fd, 0, 0);
  fds[nfd].fd = c;
  fds[nfd].events = POLLIN;
  if (nfd == limit + 1)
  {
    sprintf (buffer, "Server is busy, try again later\n");
    send (fds[nfd].fd, buffer, strlen (buffer), 0);
    close (fds[nfd].fd);
    return;
  } else
  {
    left[nfd] = 21;
    sprintf (buffer, "Matches available: %d\nTake 1, 2 or 3!\n", left[nfd]);
    send (fds[nfd].fd, buffer, strlen (buffer), 0);
    nfd++;
  }
}

// disconnects a client in case of match ending or inappropriate data sent
void dropclient (int client)
{
  int i, j;
  close (fds[client].fd);
  for (i = client; i < nfd - 1; i++)
  {
    fds[i] = fds[i + 1];
    left[i] = left[i + 1];
  }
  nfd--;
}


void make_turn (int client)
{
  int n = recv (fds[client].fd, buffer, buf_s, 0);
  if (n == 0) {
    dropclient (client);
    return;

  } else if (n > 3)
  {
    // input counts as incorrect if it contains more than 1 symbol,
    // since we expect a single digit and nothing else
    // (yep, we get two extra bytes when receiving a message)
    sprintf (buffer, "I can break rules, too. Goodbye.\n");
    send (fds[client].fd, buffer, strlen (buffer), 0);
    dropclient (client);
    return;
  }

  // way to extract a digit from the character
  int received = buffer[0] - '0';  
  if (received > 3 || received <= 0)
  {
    sprintf (buffer, "You're allowed to take 1, 2 or 3 matches only\n");
    send (fds[client].fd, buffer, strlen (buffer), 0);
    return;

  } else if (received > left[client])
  {
    sprintf (buffer, "You can't take more than %d\n", left[client]);
    send (fds[client].fd, buffer, strlen (buffer), 0);
    return;

  } else  
  {
    // obviously, it happens only when there's the only match,
    // and the client has to take it
    if (left[client] == received)
    {
      sprintf (buffer, "You lost!\n");
      send (fds[client].fd, buffer, strlen (buffer), 0);
      dropclient (client);
      return;

    } else
    {
      // sort of "keeping the game up"
      left[client] -= 4;
      sprintf (buffer, "Matches left: %d (I took %d)\n", left[client], 4 - received);
      send (fds[client].fd, buffer, strlen (buffer), 0);
      return;
    }  
  }
}

int main (int argc, char *argv[])
{
  fds[0].fd = mkservsock ();
  fds[0].events = POLLIN;

  for (;;)
  {
    int status, i;
    status = poll (fds, nfd, -1);
    if (status == -1)
      die ("Error while polling", 1);

    if (fds[0].revents & POLLIN)
      acceptclient();

    for (i = 1; i < nfd; i++)
    {
      if (fds[i].revents & POLLERR)
      {
        printf ("Got troubles on %d\n", i);
        continue;
      }

      if (fds[i].revents & POLLIN)
        make_turn (i);
    }
  }
}

And here's the thing happening to the first client after reaching max. number of connections:

Matches available: 21
Take 1, 2 or 3!

(don't take anything, meanwhile someone connects and gets rejected)

(after this, post any number and it'll say that there's only one match in the heap)

1
You lost!

Note that you lose if and only if your input is equal to a number of matches left. So, what's going on?

Copyright Notice:Content Author:「a small orange」,Reproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/13377305/strange-program-behaviour-after-closing-a-linux-socket

More about “Strange program behaviour after closing a Linux socket” related questions

Strange program behaviour after closing a Linux socket

I'm studying Linux/UNIX sockets, so I wrote a very simple "game" based on it, called "21 matches". There's a heap that consists of 21 matches, and each player takes one, two or three matches from i...

Show Detail

Linux opens the URL after closing the java program

Linux Fedora 36, GNOME 42.2, Wayland (Xorg same), Java 8 (Java 17 same) After executing the URL opening code, the URL does not open. After closing the Java program, the URL opens on its own. I have...

Show Detail

Strange Linux socket protocols behaviour

I'm a little confused about the difference between the definitions of protocols on Linux when using socket(). I am attempting to listen for connections over TCP using socket(PF_INET, SOCK_STREAM, p...

Show Detail

HTTP request, strange socket behaviour

I experience strange behavior when doing HTTP requests through sockets, here the request: POST https://example.com:443/service/XMLSelect HTTP/1.1 Content-Length: 10926 Host: example.com User-Agent:

Show Detail

Strange behaviour with direction: rtl and closing braces at the end of the sentence

I have some text with a braced part at the end and the containing div has the Css property direction: rtl;. This causes the closing brace to appear at the beginning of the sentence as opening brace...

Show Detail

basic java libgdx program runs in background after closing because of socket.io socket.connect

In a java libgdx project, the program continues running in the background on desktop even after it is closed. This is happening due to the line socket.connect(); If that line of code is removed the

Show Detail

Strange delay on Win UDP socket during GC

When closing a UDP socket which previously sent to a host known by my router, it takes forever to close. What is going on, and how can I circumvent? $ python Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb...

Show Detail

Strange behaviour of a Socket attribute in a Moose Object

I have a Moose Object which has a IO::Socket::INET object as one of its attributes: has socket =&gt; ( is =&gt; 'ro', required =&gt; 1, lazy =&gt; 1, isa =&gt; 'IO::Socket::INET&#

Show Detail

How to send data in a java socket program without closing socket

i created a sever socket program to send a stream data to Apache spark.But data is received by spark after i close the socket or termination of program.i need to send data without closing socket and

Show Detail

Strange border after closing Popup

After closing a Popup a strange border appears one of a Page element. (Page is parent of a Popup) Do you know the reason? Or maybe know the name of property that trigger this border?

Show Detail