![]() |
|
[C/C++]Basic Socket Programming - Part 1 - Printable Version +- LCKB (https://lckb.dev/forum) +-- Forum: ** OLD LCKB DATABASE ** (https://lckb.dev/forum/forumdisplay.php?fid=109) +--- Forum: Programmers Gateway (https://lckb.dev/forum/forumdisplay.php?fid=196) +---- Forum: Coders Talk (https://lckb.dev/forum/forumdisplay.php?fid=192) +---- Thread: [C/C++]Basic Socket Programming - Part 1 (/showthread.php?tid=1080) |
- someone - 09-03-2012 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; } - Wizatek - 09-08-2012 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? - Wizatek - 09-08-2012 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; } - someone - 09-08-2012 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. - someone - 09-08-2012 I wouldn't use non blocking sockets, since they are CPU intensive, You should try to use the select() function. - someone - 09-08-2012 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 - Rosario - 05-03-2013 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 |