• Welcome to TechPowerUp Forums, Guest! Please check out our forum guidelines for info related to our community.

C/C++ Sockets FAQ and How-To Win+Linux

Oliver_FF

New Member
Joined
Oct 15, 2006
Messages
544 (0.09/day)
Processor Intel q9400 @ stock
Motherboard Lanparty P45-T2RS
Cooling Zalman CNPS-9500
Memory 8GB OCZ PC2-6400
Video Card(s) BFG Nvidia GTX285 OC
Storage 1TB, 500GB, 500GB
Display(s) 20" Samsung T200HD
Case Antec Mini P180
Audio Device(s) Sound Blaster X-Fi Elite Pro
Power Supply 700w Hiper
Software Ubuntu x64 virtualising Vista
Ok so many many programs these days make use of networking and the internet. Ever wondered how simple it would be to connect two programs together over such? Wonder no further :D

What are sockets?
Well sockets are used as an interface to access a network through your operating system. Imagine your system to be contained inside of a locked room, with the only point of entry being a wall totally plastered in wall plugs. You create a socket, bind it to the plug and you've got access outside on the network. Also whilst we're at it, you can think of your firewall as a dude that stands about watching the wall plugs, pulling out ones that it doesn't like XD


Getting Started
Ok first you'll need to include the appropriate header files for sockets.
Windows
Code:
#include <winsock.h>
Pass this to GCC: /lib/libws2_32.a
winsock as in Windows Socket :eek:
Linux
Code:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
Pass these to GCC: -lsocket -lnsl
The headers for Unix are split up more so you don't get the overhead of a huge amount of stuff you just don't need!

Extra stuff for Windows...
You'll need a load of extra stuff for Windows:
Code:
WSADATA wsaData;
WSAStartup(0x0202, &wsaData);
The first line is a data structure that holds data about the current winsock version. The second line initialises the winsock component so you can use it. MISS THESE LINES AND NONE OF THIS WILL WORK :eek: :eek:

Creating your first socket
First you need to define some information about the type of connection you want to establish. Here i'm after a two-way socket (SOCK_STREAM) that uses IPv4 (AF_INET) and uses TCP (IPPROTO_TCP) for reliable data transfer. Thankfully both ways are interoperable between OS's :D
Code:
	int thisSocket;
	struct sockaddr_in destination;

	destination.sin_family = AF_INET;
	thisSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
	if (thisSocket < 0)
	{
		printf("\nSocket Creation FAILED!");
		return 0;
	}

Closing your first socket ;)
The differences here come from the way both OS's handle networking...
Windows
Code:
	closesocket(thisSocket)
	WSACleanup();
Linux
Code:
	close(thisSocket)


Hosting a connection with your socket
There are three stages to host and establish a connection:
  1. Bind the socket. Going back to this wall covered in wall plugs, this is where you take your socket and stick it into a plug.
  2. Listen on the socket. This is where you sit and wait for someone on the outside world to try to connect to your socket.
  3. Accept a connection. This is where you welcome them in and start talking.

Binding to a socket
Before you can bind to a socket you want to know what port you want to listen on. In this example i'll be listening on port "13374" because it's 1337-er than the others :cool:
The htons(int) function basically converts a port number to the type that sockets prefer.
Code:
	destination.sin_port = htons (13374);
	destination.sin_addr.s_addr = INADDR_ANY;
	if (bind(thisSocket, (struct sockaddr *)&destination, sizeof(destination))<0){
		printf("\nBinding Socket FAILED!\n");
		if (thisSocket) close(thisSocket);
		return 0;
	}

Listening on a socket
This function will BLOCK until someone tries to connect :eek:, so if your program hangs on this line and you're wondering why, it's because nobodies connected yet. The 5 refers to how many people can be trying to connect at once, not entirely sure about it tbh.
Code:
	printf("\nListening on 13374...");
	if (listen(thisSocket, 5)<0){
		printf("\nListening on Socket FAILED!\n");
		if (thisSocket) close(thisSocket);
		return 0;
	}

Accepting a connection
The last stage :). You'll need an object to get information about who you are connecting to, whose information you can read out of the struct to find out more about them after the function returns.
Code:
	struct sockaddr_in clientAddress;
	int clientSize = sizeof(clientAddress);
	thisSocket= accept(thisSocket, (struct sockaddr *)&clientAddress, (int *) &clientSize);
	if (thisSocket<0)
	{
		printf("\nSocket Connection FAILED!\n");
		if (thisSocket) close(thisSocket);
		return 0;
	}
	printf("\nConnection Established!");


Connecting to a host
Thankfully connecting to a host is blissfully simple :laugh: This will be connecting to port 13374, the same port that we should be listening on above and it'll connect to the local host (aka you) so you can try this stuff out :D
Code:
	destination.sin_port = htons(13374);
	destination.sin_addr.s_addr = inet_addr("127.0.0.1");
	if (connect(thisSocket,(struct sockaddr *)&destination,sizeof(destination))!=0){
		printf("\nSocket Connection FAILED!\n");
		if (thisSocket) close(thisSocket);
		return 0;
	}
	printf("\nConnected!");


Sending data over a socket
So you've got a socket set up at last, how do you send data over it?
The send() function takes the following:
  1. The socket you want to send data over.
  2. A char array containing your data you want to send.
  3. An int containing the amount of data in the buffer.
  4. An offset in the buffer incase you only want to send a part of it. 0 means start from the beginning.
Code:
	send(thisSocket, buffer, BUFFERSIZE, 0);


Receiving data over a socket
The revc() function takes the following:
  1. The socket you want to recieve data from.
  2. A char array you want to store the data in.
  3. The maximum size of the above array.
  4. An offset in the buffer incase. 0 starts from the beginning.
    The function returns the number of bytes that were received, up to the maximum you speficied.
    WARNING - this function BLOCKS until data arrives.
Code:
	int newData;
	newData = recv(thisSocket, buffer, BUFFERSIZE, 0);


My ways for writing for both Windows and Unix
At the top of every file I start with two lines:
Code:
#define __WINDOWS
#define __LINUX
and comment out which ever one i'm not using at the time.

This lets me do things like this:
Code:
#ifdef __WINDOWS
#include <winsock.h>
#endif
#ifdef __LINUX
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void closesocket(int socket) { close(socket); }
#endif
and
Code:
#ifdef __WINDOWS
	WSADATA wsaData;
#endif
and
Code:
#ifdef __WINDOWS
	WSAStartup(0x0202, &wsaData);
#endif
and
Code:
#ifdef __WINDOWS
    WSACleanup();
#endif

Notice how Linux makes it way easier to do networking :toast:
 
Last edited:

Kreij

Senior Monkey Moderator
Joined
Feb 6, 2007
Messages
13,817 (2.21/day)
Location
Cheeseland (Wisconsin, USA)
Great post !!!!

The last time I did any socket programming was when I was using Unix machines.
That was about 15 years ago.
Brings back memories. Not necessarily fond memories, but memories.

Keep 'em coming Oliver_FF ... we need to boost the P&W section !!!

PS. I see you've mastered the [code] tags :D
 
Last edited by a moderator:

Oliver_FF

New Member
Joined
Oct 15, 2006
Messages
544 (0.09/day)
Processor Intel q9400 @ stock
Motherboard Lanparty P45-T2RS
Cooling Zalman CNPS-9500
Memory 8GB OCZ PC2-6400
Video Card(s) BFG Nvidia GTX285 OC
Storage 1TB, 500GB, 500GB
Display(s) 20" Samsung T200HD
Case Antec Mini P180
Audio Device(s) Sound Blaster X-Fi Elite Pro
Power Supply 700w Hiper
Software Ubuntu x64 virtualising Vista
Top