Archive

Posts Tagged ‘unix’

POSIX Threads – Threading with C : Part 1

July 27th, 2009 Danny 3 comments

General

A Thread generally, is a set of instructions, that can be scheduled to run by the OS. Threads can be considered as process children, since they are created from inside a process, but a thread runs independent from the parent process. The only way they can affect each other is when a process is killed, so all child threads are killed too.

On single-processor or single-core systems, as you can imagine, two sets of instructions cannot be executed in the same time, so the processor  switches between them all the time, and in this way, making it look like they happen simultaneously.

On the other hand, multi-processor or multi-core systems, can really execute many sets of instructions in the same time, by assigning each processor / core a set.

Threads vs Processes

Processes are independent, while a thread’s execution, depends weather it’s parent is alive.

Processes use their own memory and carry many state information, while threads share their state and memory, thus making them easy for the OS to initialize.

Communication between threads is easier and faster than processes.

A big problem

peerThreads

Thread creation over time

Consider a process with two child threads. As we said, threads share the same memory. So, what happens when the two threads try to write on the same memory block? That is the main problem of parallel-computing. You might say that the odds for this to happen are way too low, but in fact, this is one of the biggest problems of big applications, which use threads to make use of multi-processor / core systems. Lately there are many ideas developed in order to bypass this problem, but that’s out of the scope of this post. Check links during the post for more information.

For the developer

Okay, since we are aware of the general idea how threads work, lets try to find out how our applications can take advantage of threading.

There are many threading standards / techniques, but we are going to stick with the most used. POSIX Threads, or pthreads. POSIX stands for “Portable Operating System Interface for Unix” and is a set of standards define by the IEEE, about API’s for Unix. pthreads are commonly used on Unix or Unix-like OS’es, but there are various implementations for Windows too, like pthreads-w32.

pthreads, defines a C library, usable with the header. This is the library we will be using to make our threaded program. Lets see a sample Hello World threaded program source :

[ helloworld_thread.c ]

[c]
#include <pthread.h>
#include <stdio.h>
#define NUM_THREADS 5

//callback function.
void hello() {
printf("Im a thread!\n");
pthread_exit(NULL);
}

int main(int argc, char *argv[]) {
pthread_t threads[NUM_THREADS]; //Declaring 5 threads.
int rc, t;
//Cycling through threads[5] to pthread_create() each thread.
for(t=0; t < NUM_THREADS; t++) {
printf("Initializing thread %d\n", t);
rc = pthread_create(&threads[t], NULL, (void *)hello, NULL); //creating each thread.
if (rc != 0){ //if pthread_create() doesn’t return 0, then we have error.
printf("ERROR; return code from pthread_create() is %d\n", rc);
return -1;
}
}
pthread_exit(NULL);
return 0;
}
[/c]

Analyzing

Let’t examine the new functions..

[c light="true"]int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine)(void*), void *arg);[/c]

  1. pthread_t *thread, a pointer to a pthread.
  2. const pthread_attr_t *attr – Attributes concerning the thread, set NULL for default attributes.
  3. void *( *start_routine)(void *) – Pointer to (void *)function that will be called by the thread.
  4. void *arg – Pointer to argument to provide to the callback function.

[c light="true"]void pthread_exit(void *retval);[/c]

This function terminates the thread with return value of void *retval.

Compiling

In order to compile a C source code using <pthread.h> we need to include the flag -pthread to our compiler, so the compile command should look like this :

[c light="true"]gcc -pthread -o helloworld_thread helloworld_thread.c[/c]

Passing Arguments

The pthread_create() function doesnt allow us to pass more than one argument to the callback function, so if we need to pass more, we have to wrap them inside a struct. Let’s see an example :

[ pthread_argument.c ]

[c]

#include <pthread.h>
#include <stdio.h>

typedef struct FOO {
int i;
int y;
} foo;

void hello(void *arg) {
foo bar = *(foo*)(arg);
printf( "This is coming from a thread:\n");
printf("arg.i = %d\narg.y = %d\n", bar.i, bar.y);
pthread_exit(NULL);
}

int main(int argc, char *argv[]) {
foo bar;
bar.i = 5;
bar.y = 6;
pthread_t mythread;
int rc, t;
printf("Initializing thread!\n");
rc = pthread_create(&mythread, NULL, (void *)hello, (void *)&bar);
if (rc != 0){
printf("ERROR; return code from pthread_create() is %d\n", rc);
return -1;
}
pthread_exit(NULL);
return 0;
}
[/c]

Passing only one argument is easy, you just cast it to (void *) before the call, and then cast it back to it's normal type from inside the callback function. But since i want to pass more arguments, i pass the struct as argument.

Resources : [ computing.llnl.gov, yolinux.com ]

Incoming Part 2 : Advanced thread parameters, joining / detaching / killing threads.

As always, you can subscribe via RSS or follow wedevblog on twitter for the latest development posts!

#include <pthread.h>
#include <stdio.h>
#define NUM_THREADS     5

void *PrintHello(void *threadid)
{
   long tid;
   tid = (long)threadid;
   printf("Hello World! It's me, thread #%ld!\n", tid);
   pthread_exit(NULL);
}

int main (int argc, char *argv[])
{
   pthread_t threads[NUM_THREADS];
   int rc;
   long t;
   for(t=0; t<NUM_THREADS; t++){
      printf("In main: creating thread %ld\n", t);
      rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
      if (rc){
         printf("ERROR; return code from pthread_create() is %d\n", rc);
         exit(-1);
      }
   }
   pthread_exit(NULL);
}
  • Share/Bookmark
Categories: dev Tags: , , , ,

C Socket Programming : Part 2

July 24th, 2009 Danny 1 comment
C Scocket Programming : Part 1

R.I.P. IPv4

IPv4 ( Internet Protocol Version 4 ) is the current, most used Internet Protocol, officially described in September 1981 by the IETF, providing 4,294,967,296 (232) addresses.

Address Exhaustion

The biggest problem of IPv4 is the address exhaustion. Back at 1980 when it was defined, nobody could imagine the incredible rate the internet grows. Nowdays every embedded device ( mobile phones, PDAs, palmtops ) is a part of the internet, thus more and more addresses need to be allocated.

Welcome IPv6

IPv6 was defined in December 1998 by the IETF, almost 20 years after the release of IPv4.

IPv6 is the next-generation Internet Protocol, designated as the successor of IPv4 which still dominates the biggest part of the internet…. For now :)

IPv6 addresses use an 128-bit encoding, thus providing about 3.4×1038 addresses and this is the main advantage of it, considering the IPv4 ( 32-bit encoding ) adrress exhaustion.

It also implements new features, additions and many more advantages but that’s not what we are here to cover :) You can read the wikipedia links for more information.

IPv6 and Network Programming

Since IPv6 will be the new internet protocol, and is already defined, why make our applications with only IPv4 in mind? We can develop our applications compatible with IPv6, but at the same time, backwards compatible with IPv4. Doing so, we put our little bit, to help IPv6 come faster, since one minor problem which slows down the successor is that many programs are not developed with IPv6 in mind.

C Sockets. Changes to make

Remember C Socket Programming : Part 1 ? Lets see what changes have to be made, in order to make our applications IPv6 compatible. Take a quick look at the examples provided at Part 1.

[c light="true"]char ip[MAX_IPV4_SIZE]; //max would be lets say 111.111.111.111 = 3×4 ( nums ) + 3×1 ( dots ) = 15[/c]

We used char ip[15] in order to store the remote host IP at our example server. But since IPv6 uses a 128-bit representation we need more space to store an IPv6 address. For this reason we use :

[c light="true"]char ip[INET6_ADDRSTRLEN];[/c]

INET6_ADDRSTRLEN is define as 45 in header file <netinet/in.h> which is included by <netdb.h> which we include ourselves.

struct addrinfo.ai_family = AF_UNSPEC;

Back when we used only IPv4, the ai_family was always AF_INET. For IPv6 we would use AF_INET6, but this would break backwards-compability with IPv4. So we use AF_UNSPEC to declare that either IPv4 or IPv6 might be used, and this will be decided during the program runtime.

struct sockaddr_storage;

The struct used to storage IPv4 family information is sockaddr_in, but because IPv6 addresses require more space, there is struct sockaddr_in6 for such a case. But if we want to be compatible with both protocols, there is struct sockaddr_storage, which can hold information for both protocols!

Using helper / wrapper functions

When we called inet_ntop() in our server example, to convert the network byte-order address into human-readable format, we passed straight their_addr.sin_addr, asssuming the remote address is IPv4. But this wont be the case with IPv6 hosts, so we have to use a helper function, that will return either sin_addr or sin6_addr, depending on struct sockaddr_storage.ss_family.

Examples redefined

So, considering those changes to be made, here are the examples of C Socket Programming : Part 1 should look like.

[ server_ipv6.c ]

[c]

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#define CON_NUM 10

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(int argc, char** argv) {
int sockfd, new_fd;
struct addrinfo hints, *servinfo;
struct sockaddr_storage their_addr;
socklen_t sin_size;
char *buff = (char*)malloc(1024);
char ip[INET6_ADDRSTRLEN];
int rc;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;

if (argc != 2) {
printf("Usage : %s PORT\n", argv[0]);
return -1;
}

if ((rc = getaddrinfo(NULL, argv[1], &hints, &servinfo)) != 0) {
printf("Error at getaddrinfo() : %s\n", gai_strerror(rc));
return 1;
}

if ((sockfd = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol)) == -1) {
printf("Error at socket() : %s\n", strerror(errno));
freeaddrinfo(servinfo);
return 1;
}

if (bind(sockfd, servinfo->ai_addr, servinfo->ai_addrlen) == -1) {
printf("Error at bind() : %s\n", strerror(errno));
freeaddrinfo(servinfo);
close(sockfd);
return -1;
}

if (listen(sockfd, CON_NUM) == -1) {
printf("Error at listen() : %s\n", strerror(errno));
freeaddrinfo(servinfo);
close(sockfd);
return -1;
}
sin_size = sizeof their_addr;
while(1) {
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
printf("Error at accept() : %s\n", strerror(errno));
continue;
}
inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr*)&their_addr), ip, sizeof ip);
printf("Got connection from %s\n", ip);
int j = 1;
while (1) {
j = recv(new_fd, buff, 1024, 0);
if ( j == 0 )
break;
if ( j == -1 ) {
printf("Error at recv() : %s\n", strerror(errno));
freeaddrinfo(servinfo);
close(sockfd);
return -1;
}
printf("Recieved : %s\n", buff);
}
}
freeaddrinfo(servinfo);
close(sockfd);
close(new_fd);
return 0;
}
[/c]

[ client.c ]

[c]

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>

int main(int argc, char** argv) {
int status, sock, bytes_sent;
struct addrinfo hints, *servinfo;
char msg[] = "hello!!";
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;

//Not correct usage, print help and exit.
if (argc != 3) {
printf("Usage : %s HOSTNAME PORT\n", argv[0]);
return -1;
}
//get info about remote host.
if ((status = getaddrinfo(argv[1], argv[2], &hints, &servinfo)) != 0) {
printf("Error during getaddrinfo() : %s\n", gai_strerror(status));
return -1;
}
//Initialize socket.
if ((sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol)) == -1) {
printf(" Error during socket() : %s\n", strerror(errno));
freeaddrinfo(servinfo); //free servinfo allocated space and exit.
return -1;
}
//connect to remote host.
if (connect(sock, servinfo->ai_addr, servinfo->ai_addrlen) == -1 ) {
printf("Error during connect() : %s\n", strerror(errno));
freeaddrinfo(servinfo);
close(sock); //Also close the socket.
return -1;
}
if ( (bytes_sent = send(sock, msg, strlen(msg), 0)) == -1 ) {
printf("Error during send() : %s\n", strerror(errno));
freeaddrinfo(servinfo);
close(sock);
return -1;
}

printf("Sent %d bytes.\n", bytes_sent);
freeaddrinfo(servinfo);
close(sock);
return 0;
}

[/c]

Resources : beej.us

Incoming Part 3 : Converting all this bunch of code, into pretty C++ Class!

As always, you can subscribe via RSS or follow wedevblog on twitter for the latest development posts!

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>

int main(int argc, char** argv) {
int status, sock, bytes_sent;
struct addrinfo hints, *servinfo;
char msg[] = “hello!!”;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;

//Not correct usage, print help and exit.
if (argc != 3) {
printf(“Usage : %s HOSTNAME PORT\n”, argv[0]);
return -1;
}
//get info about remote host.
if ((status = getaddrinfo(argv[1], argv[2], &hints, &servinfo)) != 0) {
printf(“Error during getaddrinfo() : %s\n”, gai_strerror(status));
return -1;
}
//Initialize socket.
if ((sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol)) == -1) {
printf(” Error during socket() : %s\n”, strerror(errno));
freeaddrinfo(servinfo); //free servinfo allocated space and exit.
return -1;
}
//connect to remote host.
if (connect(sock, servinfo->ai_addr, servinfo->ai_addrlen) == -1 ) {
printf(“Error during connect() : %s\n”, strerror(errno));
freeaddrinfo(servinfo);
close(sock); //Also close the socket.
return -1;
}
if ( (bytes_sent = send(sock, msg, strlen(msg), 0)) == -1 ) {
printf(“Error during send() : %s\n”, strerror(errno));
freeaddrinfo(servinfo);
close(sock);
return -1;
}

printf(“Sent %d bytes.\n”, bytes_sent);
freeaddrinfo(servinfo);
close(sock);
return 0;
}#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>

int main(int argc, char** argv) {
int status, sock, bytes_sent;
struct addrinfo hints, *servinfo;
char msg[] = “hello!!”;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;

//Not correct usage, print help and exit.
if (argc != 3) {
printf(“Usage : %s HOSTNAME PORT\n”, argv[0]);
return -1;
}
//get info about remote host.
if ((status = getaddrinfo(argv[1], argv[2], &hints, &servinfo)) != 0) {
printf(“Error during getaddrinfo() : %s\n”, gai_strerror(status));
return -1;
}
//Initialize socket.
if ((sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol)) == -1) {
printf(” Error during socket() : %s\n”, strerror(errno));
freeaddrinfo(servinfo); //free servinfo allocated space and exit.
return -1;
}
//connect to remote host.
if (connect(sock, servinfo->ai_addr, servinfo->ai_addrlen) == -1 ) {
printf(“Error during connect() : %s\n”, strerror(errno));
freeaddrinfo(servinfo);
close(sock); //Also close the socket.
return -1;
}
if ( (bytes_sent = send(sock, msg, strlen(msg), 0)) == -1 ) {
printf(“Error during send() : %s\n”, strerror(errno));
freeaddrinfo(servinfo);
close(sock);
return -1;
}

printf(“Sent %d bytes.\n”, bytes_sent);
freeaddrinfo(servinfo);
close(sock);
return 0;
}

  • Share/Bookmark
Categories: dev Tags: , , , , ,

C Socket Programming : Part 1

July 23rd, 2009 Danny 1 comment
C Socket Programming Part 2

General

Since the first years i was programming, i was always keen to applications based on communication.  Socket programming allows us to communicate with other computers / programs through networking techniques. There are 2 types of socket protocol’s that are mostly used. Those are TCP ( Stream Protocol, or SOCK_STREAM ) and UDP ( Datagram Protocol, or SOCK_DGRAM )

[table id=1 /]

For the above reasons explained, TCP/IP is the protocol used vastly on the internet, from websites, to applications. So, lets take at the steps we should make, in order to send some data over TCP to a remote PC.

  1. First of all we should have all the info required about the remote system. That includes an IP address represented in a way that our program understands, weather its IPv4 or IPv6 and if it is a hostname, do a DNS Lookup to see the IP addresses it resolves to.
  2. Initiate our socket, and feed it the data we gathered from step one.
  3. ( optional ) Bind our socket to a local port,  if we are making a server application.
  4. Connect the socket to the remote system.
  5. Send any data we want.
  6. And finally if needed, receive back other data.

Lets see how we will accomplish each task.

getaddrinfo() – magical function!!

This function will help us gather all the information ( and much more ) described in step 1 for our socket to be ready for work!

the prototype is :

[c light="true"]
int getaddrinfo(const char *node,
const char *service,
const struct addrinfo *hints,
struct addrinfo **servinfo);
[/c]

Lets examine its’ parameters..

  1. char *node – a string representing the hostname or IP that we need the information of. Pretty easy eh? :)
  2. char *service – a string that can either represent a port ( eg “80″ ), or the name of a service ( eg “http” ), which are both equivalent.
  3. struct addrinfo *hints – points to an addrinfo struct which we have already filled out with various infrmation. We will get soon on that.
  4. struct addrinfo **servinfo – a pointer-to-pointer addrinfo struct, for which the function will allocate the required memory, and fill in the information we need to know about the *node.

Here is an example call to getaddrinfo() :

[c]

#include <string.h> //memset()
#include <sys/types.h> //struct definitions
#include <sys/socket.h> //getaddrinfo()
#include <netdb.h> //AI_PASSIVE definition.

int main() {
int status;
struct addrinfo hints;
struct addrinfo *servinfo;  // will point to the results

memset(&hints, 0, sizeof hints); // make sure the struct is empty
hints.ai_family = AF_UNSPEC;     // don’t care IPv4 or IPv6
hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
hints.ai_flags = AI_PASSIVE;     // fill in my IP for me

if ((status = getaddrinfo("www.example.com", "80", &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
return 1;
}
// servinfo now points to a linked list of 1 or more struct addrinfos
// … do everything until you don’t need servinfo anymore ….
freeaddrinfo(servinfo); // free the linked-list
return 0;
}
[/c]

So, now that we have the information needed about example.com, we want to create a socket, and later on, connect to it.

Gief my socket!

As you may know, or have heard, in Unix, everything is files! Well, before you say that the word “everything” is too-much, and start arguing, i mean that everything that is about I/O ( files, devices etc ) is a file descriptor. I guess you are familiar with file I/O in C. Well, guess what! It is the same with sockets! Lets take a peek at the prototype of the function which initiates a socket.

[c light="true"]int socket(int domain, int type, int protocol); [/c]

  1. int domain – PF_INET for IPv4, PF_INET6 for IPv6
  2. int type – SOCK_STREAM for TCP, SOCK_DGRAM for UDP.
  3. int protocol – set to zero, so the function will choose the right protocol, according to the other parameters.

But before running to your text editor and calling the function, let me make you happy!! All those parameters are provided from the addrinfo struct which getaddrinfo() filled out for us!! See why its a magical function? :)

So, using those resources, the socket() call is like this :

[c light="true"]

int s;

s = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);

[/c]

I need a port!

The next step, is to bind our socket  ( if needed ) to a local port and then listen on it for incoming connections.

[c light="true"]int bind(int sockfd, struct sockaddr *my_addr, int addrlen);[/c]

Return Value

bind() will return -1 on error, and set errno accordingly.

to understand how it works, here is an example :

[c]#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

int main() {
struct addrinfo hints, *res;
int sockfd;
// first, load up address structs with getaddrinfo():
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;  // use IPv4 or IPv6, whichever
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;     // fill in my IP for me

getaddrinfo(NULL, "3490", &hints, &res);

// make a socket:

sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);

// bind it to the port we passed in to getaddrinfo():

bind(sockfd, res->ai_addr, res->ai_addrlen);
close(socket);
freeaddrinfo(res);
return 0;
}

[/c]

By passing AI_PASSIVE to hints.ai_flags we instruct that we will bind to the host where the program is running, and for this reason, the first argument of getaddrinfo() is NULL.
If we wanted to bind on another IP or host, we define it as the first argument of getaddrinfo() and bypass the AI_PASSIVE statement. Right now, our program is not ready to recieve connections, it is just binded on a port. How to listen() on this port will be explained later. Also, keep in mind that binding on ports below 1024 is not allowed, unless you are superuser. All other ports, 1024 to 65535 can be used by you, without superuser privilege, unless they are used by another program.

Connection Initialized…

So, now we are allowed to connect to a remote IP address / hostname ( or even local! ). This is achieved using the connect() function.

[c light="true"]int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);[/c]

  1. int sockfd – The socket file descriptor returned from a socket() call.
  2. struct sockaddr *serv_addr – a sockaddr structure containing the IP address and port.
  3. int addrlen – The number in bytes of the server address structure.

Lucky for us, arguments 2 and 3, are provided from the getaddrinfo() call! Yeah!

Return Value

If connect() was unsuccessful it returns -1 and sets errno accordingly. We will cover how to read errno later.

send() and recv()

Now that we are connected to a remote host, we can send() data to him and he can then recv() our data. Lets see the prototypes :

[c light="true"]int send(int sockfd, const void *msg, int len, int flags);[/c]

  1. int sockfd – The file descriptor returned by socket()
  2. void *msg – Pointer to the data to be sent.
  3. int len – Length of msg in bytes.
  4. int flags – Set to zero.

Return Value

send() will return the number of bytes sent, which might not be same as len! So it’s our responsibility to send all the remaining data. The good news is that packets of size 1kB are usually packed into one packet. Now lets see recv().

If there was an error, -1 will be returned, and errno will be set accordingly.

[c light="true"]int recv(int sockfd, void *buf, int len, int flags);[/c]

  1. int sockfd – The file descriptor returned by socket()
  2. void *buf – A buffer where data read are written.
  3. int len – Length of buf in bytes.
  4. int flags – Set to zero.

Return Value

recv() will return the number of bytes read, which might not be all the data the sender wanted to send. For this reason, zero is returned in case where the connection has been closed, so that we can assume that no more data are to be read.

In case of error, recv() returns -1 and sets errno accordingly.

A lot of informations these are, right? Lets sum up all those information into a real example.

Server – Client example

What’s the best way to put all together what we learned? :)

Server that waits for connections, and prints the message it recieves :

[ server.c ]

[c light="true"]

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#define CON_NUM 10
#define MAX_IPV4_SIZE 15

int main(int argc, char** argv) {
int sockfd, new_fd;
struct addrinfo hints, *servinfo;
struct sockaddr_in their_addr;
socklen_t sin_size;
char *buff = (char*)malloc(1024);
char ip[MAX_IPV4_SIZE]; // max would be lets say 111.111.111.111 = 3×4 ( nums ) + 3×1 ( dots ) = 15
int rc;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;

if (argc != 2) {
printf("Usage : %s PORT\n", argv[0]);
return -1;
}

if ((rc = getaddrinfo(NULL, argv[1], &hints, &servinfo)) != 0) {
printf("Error at getaddrinfo() : %s\n", gai_strerror(rc));
return 1;
}

if ((sockfd = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol)) == -1) {
printf("Error at socket() : %s\n", strerror(errno));
freeaddrinfo(servinfo);
return 1;
}

if (bind(sockfd, servinfo->ai_addr, servinfo->ai_addrlen) == -1) {
printf("Error at bind() : %s\n", strerror(errno));
freeaddrinfo(servinfo);
close(sockfd);
return -1;
}

if (listen(sockfd, CON_NUM) == -1) {
printf("Error at listen() : %s\n", strerror(errno));
freeaddrinfo(servinfo);
close(sockfd);
return -1;
}
sin_size = sizeof their_addr;
while(1) {
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
printf("Error at accept() : %s\n", strerror(errno));
continue;
}
inet_ntop(their_addr.sin_family, (struct sockaddr*)&their_addr.sin_addr, ip, sizeof ip);
printf("Got connection from %s\n", ip);
int j = 1;
while (1) {
j = recv(new_fd, buff, 1024, 0);
if ( j == 0 )
break;
if ( j == -1 ) {
printf("Error at recv() : %s\n", strerror(errno));
freeaddrinfo(servinfo);
close(sockfd);
return -1;
}
printf("Recieved : %s\n", buff);
}
}
freeaddrinfo(servinfo);
close(sockfd);
close(new_fd);
return 0;
}

[/c]

Client that send’s a msg to a server.
[ client.c ]

[c]
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#define HOSTNAME "localhost"
#define PORT "1235"

int main(int argc, char** argv) {
int status, sock, bytes_sent;
struct addrinfo hints, *servinfo;
char msg[] = "hello!!";
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;

//Not correct usage, print help and exit.
if (argc != 3) {
printf("Usage : %s HOSTNAME PORT\n", argv[0]);
return -1;
}
//get info about remote host.
if ((status = getaddrinfo(argv[1], argv[2], &hints, &servinfo)) != 0) {
printf("Error during getaddrinfo() : %s\n", gai_strerror(status));
return -1;
}
//Initialize socket.
if ((sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol)) == -1) {
printf(" Error during socket() : %s\n", strerror(errno));
freeaddrinfo(servinfo); //free servinfo allocated space and exit.
return -1;
}
//connect to remote host.
if (connect(sock, servinfo->ai_addr, servinfo->ai_addrlen) == -1 ) {
printf("Error during connect() : %s\n", strerror(errno));
freeaddrinfo(servinfo);
close(sock); //Also close the socket.
return -1;
}
if ( (bytes_sent = send(sock, msg, strlen(msg), 0)) == -1 ) {
printf("Error during send() : %s\n", strerror(errno));
freeaddrinfo(servinfo);
close(sock);
return -1;
}

printf("Sent %d bytes.\n", bytes_sent);
freeaddrinfo(servinfo);
close(sock);
return 0;
}</pre>
[/c]

Resources : beej.us

Incoming Part 2 : Defining IPv6, how to make your networking application, IPv6 compatible, and IPv4 backwards compatible.

Incoming Part 3 : Converting all this bunch of code, into pretty C++ Class! Don’t miss them!

As always, you can subscribe via RSS or follow wedevblog on twitter for the latest development posts!

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#define CON_NUM 10
#define MAX_IPV4_SIZE 15int main(int argc, char** argv) {
int sockfd, new_fd;
struct addrinfo hints, *servinfo;
struct sockaddr_in their_addr;
socklen_t sin_size;
char *buff = (char*)malloc(1024);
char ip[MAX_IPV4_SIZE]; // max would be lets say 111.111.111.111 = 3×4 ( nums ) + 3×1 ( dots ) = 15
int rc;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;

if (argc != 2) {
printf(“Usage : %s PORT\n”, argv[0]);
return -1;
}

if ((rc = getaddrinfo(NULL, argv[1], &hints, &servinfo)) != 0) {
printf(“Error at getaddrinfo() : %s\n”, gai_strerror(rc));
return 1;
}

if ((sockfd = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol)) == -1) {
printf(“Error at socket() : %s\n”, strerror(errno));
freeaddrinfo(servinfo);
return 1;
}

if (bind(sockfd, servinfo->ai_addr, servinfo->ai_addrlen) == -1) {
printf(“Error at bind() : %s\n”, strerror(errno));
freeaddrinfo(servinfo);
close(sockfd);
return -1;
}

if (listen(sockfd, CON_NUM) == -1) {
printf(“Error at listen() : %s\n”, strerror(errno));
freeaddrinfo(servinfo);
close(sockfd);
return -1;
}
sin_size = sizeof their_addr;
while(1) {
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
printf(“Error at accept() : %s\n”, strerror(errno));
continue;
}
inet_ntop(their_addr.sin_family, (struct sockaddr*)&their_addr.sin_addr, ip, sizeof ip);
printf(“Got connection from %s\n”, ip);
int j = 1;
while (1) {
j = recv(new_fd, buff, 1024, 0);
if ( j == 0 )
break;
if ( j  == -1 ) {
printf(“Error at recv() : %s\n”, strerror(errno));
freeaddrinfo(servinfo);
close(sockfd);
return -1;
}
printf(“Recieved : %s\n”, buff);
}
}
freeaddrinfo(servinfo);
close(sockfd);
close(new_fd);
return 0;
}

  • Share/Bookmark
Categories: dev Tags: , , , ,