[C/C++]Basic Socket Programming - Part 1
#1

This tutorial will show you how to make an basic socket client server communcaions:

Basic Client:

//general libraries
#include <stdio.h>

// platform specific libraries
#ifdef WIN32
#include <winsock2.h>
// check if its visual c++
#ifdef _MSC_VER
#pragma comment(lib,"ws2_32.lib")
#endif
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#endif

// client starting up function
int startupClient(const char* serverName, unsigned short port) {
// for errors
int error;

// windows winsock init
#ifdef WIN32
WSAData wsaData;

// startup winsock
if ((error = WSAStartup(MAKEWORD(2, 2), &wsaData)) < 0) {
printf("Could Not Start Up Winsock!\n");
return -1;
}
#endif

// create a clientSocket for the client
int clientSocket = socket(AF_INET, SOCK_STREAM, 0);

// check if it could create a socket
if (clientSocket < 0) {
printf("Error Opening Socket!\n");
return -1;
}

// get the host entry from the client
// gethostbyname converts from Domain, IP to hostent structure
struct hostent *host_entry;
if ((host_entry = gethostbyname(serverName)) == NULL) {
printf("Could not find host!\n");
}

// init server connection info
struct sockaddr_in server;
memset(&server, 0, sizeof(sockaddr_in));

// server connection info
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = *(unsigned long*) host_entry->h_addr;

// connect to the server
if (connect(clientSocket, (sockaddr*)&server, sizeof(server)) < 0) {
printf("Error connecting to server!\n");
}
printf("Client Started\n");

return clientSocket;
}

// socket shutdown function
void shutdownSocket(int clientSocket) {
#ifdef WIN32
// close our socket
closesocket(clientSocket);

// shut down winsock
WSACleanup();
#else
// close our socket
close(clientSocket);
#endif
printf("Client Shutdown\n");
}

// the application entry point
int main(){
int Socket = startupClient("10.0.0.1", 12345);
if(Socket < 0){
// error, shuting down socket and close app
shutdownSocket(Socket);
return 1;
}

// sending data
char message[]="MyMessage";
send(Socket, message, strlen(message), 0);

// receiving data
char message2[20]={0};
recv(Socket, message2, sizeof(message2), 0);

return 0;
}

 

Basic Server:

//general libraries
#include <stdio.h>

// platform specific libraries
#ifdef WIN32
#include <winsock2.h>
// check if its visual c++
#ifdef _MSC_VER
#pragma comment(lib,"ws2_32.lib")
#endif
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#endif

// server startup listening only on 1 IP
int startupServer(const char* serverName, unsigned short port) {
// windows winsock init
#ifdef WIN32
// the winsock data structure
WSAData wsaData;

// startup winsock
if (WSAStartup(MAKEWORD(2, 2), &wsaData) < 0) {
printf("Could Not Start Up Winsock!\n");
return -1;
}
#endif

// create a server Socket for the client
int Socket = socket(AF_INET, SOCK_STREAM, 0);

// check if it could create a socket
if (Socket < 0) {
printf("Error Opening Socket!\n");
return -1;
}

// init server connection info
struct sockaddr_in server;
memset(&server, 0, sizeof(sockaddr_in));

// server connection info
server.sin_family = AF_INET;
server.sin_port = htons(port);

// get the host entry from the client
// gethostbyname converts from Domain, IP to hostent structure
struct hostent *host_entry;
if ((host_entry = gethostbyname(serverName)) == NULL) {
printf("Could not find host!, trying by address \n");
server.sin_addr.s_addr = inet_addr(serverName);
}else{
server.sin_addr.s_addr = *(unsigned long*) host_entry->h_addr;
}
// till now its the same as startupClient
// instead of connect we bind and listen for new connectios

// bind the server to an IP
if (bind(Socket, (sockaddr*)&server, sizeof(server)) < 0) {
printf("Bind Failed!\n");
return -1;
}

// listen for new connections
if (listen(Socket, 5) < 0) {
printf("Listen Failed!\n");
return -1;
}

printf("Server Started\n");

return Socket;
}

//start up server listening on all interfaces
int startupServer(unsigned short port) {
//0.0.0.0 means all networks
return startupServer("0.0.0.0", port);
}

// Server shutdown function
void shutdownSocket(int clientSocket) {
#ifdef WIN32
// close our socket
closesocket(clientSocket);

// shut down winsock
WSACleanup();
#else
// close our socket
close(clientSocket);
#endif
printf("Client Shutdown\n");
}

// the application entry point
int main(){
int Socket = startupServer("10.0.0.1", 12345);
if(Socket < 0){
// error, shuting down socket and close app
shutdownSocket(Socket);
return 1;
}

// new socket for every client,
// you could create a socket wheel using a for loop to handle many clients
int clientSocket;
clientSocket = accept(Socket, 0, 0);

// check for errors
if (clientSocket < 0) {
printf("Accept Failed!\n");
}

// receiving data
char message2[20]={0};
int nBytes = recv(clientSocket, message2, sizeof(message2), 0);

switch(nBytes){
case 0: {
// client disconnected
break;
}
case -1:{
// if it's nonBlocking sochets you didnt received anything
break;
}
default:
// the message received from client
if(!strcmp(message2, "MyMessage")){
// sending data
char message[]="MyMessage";
send(clientSocket, message, strlen(message), 0);
}
}
return 0;
}

#2

Awesome, works like a charm in code::blocks

Only had to add the wsock lib in the linker.

 

How would we go from here to make a non blocking or async socket system?

Create a worker socket from the main socket and free it?

#3

After some searching i found this easy example

 

#include <winsock2.h>
#include <iostream>

#include <stdio.h>
#include <stdlib.h>

#define DEFAULT_PORT 4101
#define DEFAULT_ADDRESS "127.0.0.1"
#define DEFAULT_BUFFER 4096

int iPort = DEFAULT_PORT; // Port to listen for clients on
BOOL bInterface = FALSE, // Listen on the specified interface
bRecvOnly = FALSE; // Receive data only; don't echo back
char szAddress[128]; // Interface to listen for clients on

void test(char* packet, int len)
{
char* str = packet;
for (int p=0; p<len;p++)
{
printf("%x ", packet[p]);
}
printf("\n");

}

//
// Function: ClientThread
//
// Description:
// This function is called as a thread, and it handles a given
// client connection. The parameter passed in is the socket
// handle returned from an accept() call. This function reads
// data from the client and writes it back.
//
DWORD WINAPI ClientThread(LPVOID lpParam)
{
SOCKET sock=(SOCKET)lpParam;
char szBuff[DEFAULT_BUFFER];
int ret,
nLeft,
idx;

while(1)
{
// Perform a blocking recv() call
//
ret = recv(sock, szBuff, DEFAULT_BUFFER, 0);
if (ret == 0) // Graceful close
break;
else if (ret == SOCKET_ERROR)
{
printf("recv() failed: %d\n", WSAGetLastError());
break;
}
szBuff[ret] = '\0';
printf("RECV[%d]: '%s'\n",ret, szBuff);

test(szBuff,ret);
//
// If we selected to echo the data back, do it
//
if (!bRecvOnly)
{
nLeft = ret;
idx = 0;
//
// Make sure we write all the data
//
while(nLeft > 0)
{
ret = send(sock, &szBuff[idx], nLeft, 0);
if (ret == 0)
break;
else if (ret == SOCKET_ERROR)
{
printf("send() failed: %d\n",
WSAGetLastError());
break;
}
nLeft -= ret;
idx += ret;
}
}
}
return 0;
}

//
// Function: main
//
// Description:
// Main thread of execution. Initialize Winsock, parse the
// command line arguments, create the listening socket, bind
// to the local address, and wait for client connections.
//
int main(int argc, char **argv)
{
WSADATA wsd;
SOCKET sListen,
sClient;
int iAddrSize;
HANDLE hThread;
DWORD dwThreadId;
struct sockaddr_in local,
client;

if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
{
printf("Failed to load Winsock!\n");
return 1;
}
// Create our listening socket
//
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (sListen == SOCKET_ERROR)
{
printf("socket() failed: %d\n", WSAGetLastError());
return 1;
}
// Select the local interface and bind to it
//
if (bInterface)
{
local.sin_addr.s_addr = inet_addr(szAddress);

}
else
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(iPort);

if (bind(sListen, (struct sockaddr *)&local,
sizeof(local)) == SOCKET_ERROR)
{
printf("bind() failed: %d\n", WSAGetLastError());
return 1;
}
listen(sListen, 8);
//
// In a continous loop, wait for incoming clients. Once one
// is detected, create a thread and pass the handle off to it.
//
while (1)
{
printf("Listening..");
iAddrSize = sizeof(client);
sClient = accept(sListen, (struct sockaddr *)&client,
&iAddrSize);
if (sClient == INVALID_SOCKET)
{
printf("accept() failed: %d\n", WSAGetLastError());
break;
}
printf("Accepted client: %s:%d\n",
inet_ntoa(client.sin_addr), ntohs(client.sin_port));

hThread = CreateThread(NULL, 0, ClientThread,
(LPVOID)sClient, 0, &dwThreadId);
if (hThread == NULL)
{
printf("CreateThread() failed: %d\n", GetLastError());
break;
}
CloseHandle(hThread);
}
closesocket(sListen);

WSACleanup();
return 0;
}

#4

For non-Blocking Sockets its easy:

 

Create a Function That will apply the nonblocking to the sochet:

// where iMode =1 enable nonblocking, iMode = 0 Disable nonblocong
int applyNonBlocking(int Socket,int iMode){
int result = -1; //Socket_error
#ifdef WIN32
u_long opt = (u_long)iMode;
//activate nonblocking sockets
result = ioctlsocket(Socket,FIONBIO, &opt);
#else
//activate nonblocking sockets
result = ioctl(Socket, FIONBIO, &iMode);
#endif
return result;
}

 

Then after Accepting a client you can apply nonblocking sockets:

// new socket for every client,
// you could create a socket wheel using a for loop to handle many clients
int clientSocket;
clientSocket = accept(Socket, 0, 0);

//apply nonBlocking to the client sockets
applyNonBlocking(clientSocket, 1);

// the server accepting clients will be blocked(unless you want to applynonBlocking to Socket),
// but the communication client/server will ne nonBlocked

 

If you want nonBlocing on the client you can simply Apply Apply socket after you created a socket.[/code]

 

For async usually is Win32 programming.

 

 

To create an worker sockets it will require to know threads, there are 3 ways to create a thread:

1) by using windows threads(limited to windows)

2) By using POSIX threads(which is not limited to OS)

3)You can use MPI(Mwssage Passing Interface).

 

 

I'll post a separate tutorial in Pthreads, and windows Threads, to not make it make this thred too complex.

#5
I wouldn't use non blocking sockets, since they are CPU intensive, You should try to use the select() function.

#6


Its because in my language the function for receiving data doesn't return 0 when its empty. As I code my threads to loop on checking if data is received from that that socket until something is received. Once it receives data it breaks and goes into parsing the data received. At the moment it returns -1 on error, and -1 when no data is received. So its hard to know if the client disconnected, or is just idling.

You can just put a timeout for the the last packet received(30 seconds I think its enough), plus it will disconnect those who have the client opened with a debugger.

 

Or you could use WSAGetLastError_() to get the error code and compare it with some of this:

2

 

The most necessary are:

WSAECONNRESET 10054 ->means the application either was closed or it lost connection

WSAEDISCON 10101 ->client disconnected(like receiving 0)

There are other like timeout, etc

#7

Guys sorry for being a  Noob here but could someone please dumb this all down for me please?

Just I really want to learn about C++ Programming and everything about C++ but Im nothing like

Seldon from The Big Bang Theory or anything like you Guys/Gals... 

 

Whats the best and easier way to learn about this sort of thing?

Ive been reading stuff on the net though but am idk... 

 

Sorry if this is a Stupid Noobish Question etc...  :mellow:

Am Trying to learn though as already stated! 

 

Thanks a lot Big Grin 



Forum Jump:


Users browsing this thread: 1 Guest(s)