Categories
Programming

C CRITICAL_SECTION in windows2 min read

CRITICAL_SECTION (MSDN) in Windows can be used for thread synchronization. Essentially you can create a variable and limit it’s ownership to one thread at a time.  Something like this

CRITICAL_SECTION cs;

volatile long counter = 0;

int main(){
  InitializeCriticalSection(&cs);

  //Create threads and run thread_func
  //.....
  //.....
}

void thread_func (){
  //Get ownership of counter
  EnterCriticalSection(&cs);

  //Increment counter
  counter++;

  printf("No. of threads run: %d\n", counter);

  //Leave ownership of counter
  //so that other threads can have it
  LeaveCriticalSection(&cs);
}

Threads block while waiting for ownership of counter . So only one thread will have access to counter  at a time.

Earlier we have created a TCP server using winsock (https://jijnasu.in/c-tcp-server-in-windows-thread-per-connection/). Let’s make use of CRITICAL_SECTION to count the number of requests served by our server.

#include <winsock.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>

#define PORT 50001

//Function that threads run
static DWORD __stdcall func(int s);

//Function to set no. of req served
static void __stdcall inc();

//CRITICAL_SECTION variable
CRITICAL_SECTION cs;

/*
(long counter) to count the
number of requests served.
Volatile so that the
value is read from memory
and not cache
(I think so)
*/
volatile long counter = 0;

int main() {
    //Dont ask just put it in there
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
        fprintf(stderr, "WSAStartup failed.\n");
        exit(1);
    }

    //Socket initiation
    int sock;
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
        printf("Socket initiation failed!");
        return 0;
    }

    //Socket settings
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    memset(addr.sin_zero, '\0', sizeof addr.sin_zero);

    //Bind the socket
    int b;
    if ((b = bind(sock, &addr, sizeof(addr))) == SOCKET_ERROR) {
        printf("Socket initiation failed!");
        return 0;
    }

    //Listen on socket
    int l = listen(sock, 25);

    //Initialize CRITICAL_SECTION
    InitializeCriticalSection(&cs);

    printf("TCP server listening on port %d\n", PORT);

    //If (con) pass it to a new thread
    while (1) {
        struct sockaddr_in client_addr;
        unsigned int c_len = sizeof client_addr;
        int s1 = accept(sock, &client_addr, &c_len);
        unsigned int cur_tid;

        _beginthreadex(NULL, 0, func, s1, 0, &cur_tid);
    }

    //Cleanup
    closesocket(sock);
    WSACleanup();
    return 0;
}

static DWORD __stdcall func(int s) {
    puts("Connection accepted");

    //Read data from client
    char buff[1024];
    unsigned int tot_bytes = recv(s, buff, sizeof(buff), MSG_PEEK);
    char * client_data = (char *)malloc(tot_bytes + 1);
    for (int i = 0; i < (tot_bytes); i++) {
        client_data[i] = buff[i];
    }
    client_data[tot_bytes] = '\0';

    printf("Msg from client: %s\n", client_data);

    //Pretend you are processing info
    puts("Processing req");
    Sleep(5000);
    puts("Processing complete");

    //Prepare message for the client
    char * message;
    if (strcmp(client_data, "COMMAND1") == 0) {
        char lmsg[] = "COMMAND1 recieved";
        message = (char *)malloc(strlen(lmsg));
        message = lmsg;
    }
    else if (strcmp(client_data, "COMMAND2") == 0) {
        char lmsg[] = "COMMAND2 recieved";
        message = (char *)malloc(strlen(lmsg));
        message = lmsg;
    }
    else {
        char lmsg[] = "NO COMMAND recieved";
        message = (char *)malloc(strlen(lmsg));
        message = lmsg;
    }

    free(client_data);

    //Send data to client
    send(s, message, strlen(message), 0);

    inc();

    return 0;
}

static void __stdcall inc() {
    EnterCriticalSection(&cs);
    counter++;
    printf("No. of reqs served: %d\n", counter);
    LeaveCriticalSection(&cs);
}

 

Categories
Programming

C TCP Server in Windows – Thread per connection2 min read

A simple TCP server in C (windows). It works in a “thread per connection” way.

Note- I don’t know what I am doing.

#include <winsock.h> 
#include <stdio.h> 
#include <string.h> 
#include <sys/types.h>

#define PORT 50001

//Function that threads run
static DWORD __stdcall func(int s);

int main() {
  //Dont ask just put it in there
  WSADATA wsaData;
  if (WSAStartup(MAKEWORD(2, 0), & wsaData) != 0) {
    fprintf(stderr, "WSAStartup failed.\n");
    exit(1);
  }

  //Socket initiation
  int sock;
  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
    printf("Socket initiation failed!");
    return 0;
  }

  //Socket settings
  struct sockaddr_in addr;
  addr.sin_family = AF_INET;
  addr.sin_port = htons(PORT);
  addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  memset(addr.sin_zero, '\0', sizeof addr.sin_zero);

  //Bind the socket
  int b;
  if ((b = bind(sock, & addr, sizeof(addr))) == SOCKET_ERROR) {
    printf("Socket initiation failed!");
    return 0;
  }

  //Listen on socket
  int l = listen(sock, 25);

  printf("TCP server listening on port %d\n", PORT);

  //If (con) pass it to a new thread 
  while (1) {
    struct sockaddr_in client_addr;
    unsigned int c_len = sizeof client_addr;
    int s1 = accept(sock, & client_addr, & c_len);
    unsigned int cur_tid;

    _beginthreadex(NULL, 0, func, s1, 0, & cur_tid);
  }

  //Cleanup
  closesocket(sock);
  WSACleanup();
  return 0;
}

static DWORD __stdcall func(int s) {
  puts("Connection accepted");

  //Read data from client
  char buff[1024];
  unsigned int tot_bytes = recv(s, buff, sizeof(buff), MSG_PEEK);
  char * client_data = (char * ) malloc(tot_bytes + 1);
  for (int i = 0; i < (tot_bytes); i++) {
    client_data[i] = buff[i];
  }
  client_data[tot_bytes] = '\0';

  printf("Msg from client: %s\n", client_data);

  //Pretend you are processing info
  puts("Processing req");
  Sleep(5000);
  puts("Processing complete");

  //Prepare message for the client
  char * message;
  if (strcmp(client_data, "COMMAND1") == 0) {
    char lmsg[] = "COMMAND1 recieved";
    message = (char * ) malloc(strlen(lmsg));
    message = lmsg;
  } else if (strcmp(client_data, "COMMAND2") == 0) {
    char lmsg[] = "COMMAND2 recieved";
    message = (char * ) malloc(strlen(lmsg));
    message = lmsg;
  } else {
    char lmsg[] = "NO COMMAND recieved";
    message = (char * ) malloc(strlen(lmsg));
    message = lmsg;
  }

  free(client_data);

  //Send data to client
  send(s, message, strlen(message), 0);

  return 0;
}

TCP client in Node.js

var net = require('net');

var client1 = new net.Socket();
client1.connect(50001, '127.0.0.1', function() {
  console.log('Connected');
  client1.write('COMMAND1');
});

client1.on('data', function(data) {
  console.log('Received on 1: ' + data);
  client1.destroy();
});

client1.on('close', function() {
  console.log('Connection closed on 1');
});

var client2 = new net.Socket();
client2.connect(50001, '127.0.0.1', function() {
  console.log('Connected on 2');
  client2.write('COMMAND2');
});

client2.on('data', function(data) {
  console.log('Received on 2: ' + data);
  client2.destroy();
});

client2.on('close', function() {
  console.log('Connection closed on 2');
});

See single threaded windows TCP server using IO Completion Ports – https://github.com/hrishimk/iocp_tcp_server