950 likes | 1.16k Views
Part 1. Socket Programming. IPv6 ready. C/C++ Language. Getting Started…. WinSock Functions Predefined constants and error codes Special Structures, Unions and data types suited for socket programming Correct order of function calls to synchronize Server and Client applications.
E N D
Part 1 Socket Programming IPv6 ready C/C++ Language
Getting Started… • WinSock Functions • Predefined constants and error codes • Special Structures, Unions and data types suited for socket programming • Correct order of function calls to synchronize Server and Client applications
Socket Programming Goal: learn how to build client/server application that communicate using sockets socket a host-local, application-created/owned, OS-controlled interface (a "door") into which application process can both send and receive messages to/from another (remote or local) application process Socket API • introduced in BSD4.1 UNIX, 1981 • explicitly created, used, released by applications • uses client/server paradigm • two types of transport service via socket API: • unreliable datagram • reliable, byte stream-oriented • WinSock 2 - to provide a protocol-independent transport interface that is fully capable of supporting emerging networking capabilities including real-time multimedia communications
Socket Programming using TCP controlled by application developer controlled by application developer process process socket socket TCP with buffers, variables controlled by operating system TCP with buffers, variables controlled by operating system Internet client or server client or server Socket: a door between application process and end-end-transport protocol (UDP or TCP) TCP service: reliable transfer of bytesfrom one process to another
When contacted by client, server TCP creates new socket for server process to communicate with client allows server to talk with multiple clients Socket Programming with TCP Application Viewpoint TCP provides reliable, in-order transfer of bytes ("pipe") between client and server Client must contact server • server process must first be running • server must have created socket (“door”) that welcomes client’s contact Server socket “Client knocking on the door” Client contacts server by: creating client-local TCP socket specifying IP address, port number of server process
Socket Programming with TCP Example of a client-server application: • Client reads line from standard input • Client sends to server via socket • Server reads line from socket • Server counts the number of bytes contained in the line and sends it back to client • Client reads and prints the message stating how many bytes it has sent originally
Client/server socket interaction: TCP create socket, connect to hostid, port=x create socket, port=x, for incoming request: clientSocket = socket() welcomeSocket = socket() TCP connection setup wait for incoming connection request connectionSocket = accept() send request using clientSocket read request from connectionSocket write reply to connectionSocket read reply from clientSocket close connectionSocket close clientSocket Server(running on hostid) Client Application 2-8
Proper Ordering of Send and Recv socket connect /* communicate with server*/ loop until done { send receive } closesocket(socket) socket bind listen loop "forever" { accept /* by creating newsocket*/ /* communicate with client*/ loop until done { receive send } closesocket(newsocket) }
Simple Client-Server TCP Control Socket C Listening Socket S Temporary TCP Socket for Client Server • In TCP, the Server should be running already prior to a Client connecting to it
stream is a sequence of characters that flow into or out of a process. input stream is attached to some input source for the process, e.g., keyboard or socket. output stream is attached to an output source, e.g., monitor or socket. Stream jargon Client process client TCP socket Application 2-11
Client/Server Socket Interaction: UDP • No handshaking - has no connection establishment • No streams are attached to the sockets. • Sender creates packets of bytes with IP destination address Port number. • Receiving host must unravel each packet received to obtain the packet’s information bytes. UDP (User Datagram Protocol) • –No connection state at servers • less packet overhead than TCP • light error-checking (checksum) • server doesn’t use the listen() function • server doesn’t use the accept() function
Client/server socket interaction: UDP Client create socket, clientSocket = Socket() Create datagram with server (hostid, port=x), send datagram viaclientSocket read datagram from serverSocket write reply to serverSocket specifying client address, port number read datagram from clientSocket close clientSocket Server (running on hostid) create socket, port= x. serverSocket = Socket() Application 2-14
Some utility: Netstat Netstat -a Active Connections Proto Local Address Foreign Address State TCP IT027049:http IT027049.massey.ac.nz:0 LISTENING TCP IT027049:epmap IT027049.massey.ac.nz:0 LISTENING TCP IT027049:https IT027049.massey.ac.nz:0 LISTENING TCP IT027049:microsoft-ds IT027049.massey.ac.nz:0 LISTENING TCP IT027049:1025 IT027049.massey.ac.nz:0 LISTENING TCP IT027049:1179 IT027049.massey.ac.nz:0 LISTENING TCP IT027049:1181 IT027049.massey.ac.nz:0 LISTENING TCP IT027049:1300 IT027049.massey.ac.nz:0 LISTENING TCP IT027049:1318 IT027049.massey.ac.nz:0 LISTENING TCP IT027049:1786 IT027049.massey.ac.nz:0 LISTENING TCP IT027049:1787 IT027049.massey.ac.nz:0 LISTENING TCP IT027049:1790 IT027049.massey.ac.nz:0 LISTENING TCP IT027049:1791 IT027049.massey.ac.nz:0 LISTENING TCP IT027049:5000 IT027049.massey.ac.nz:0 LISTENING TCP IT027049:13450 IT027049.massey.ac.nz:0 LISTENING TCP IT027049:netbios-ssn IT027049.massey.ac.nz:0 LISTENING TCP IT027049:1082 IT027049.massey.ac.nz:0 LISTENING TCP IT027049:1179 its-xchg4.massey.ac.nz:1165 ESTABLISHED TCP IT027049:1181 its-dc2.massey.ac.nz:1025 ESTABLISHED TCP IT027049:1318 hnt-up-dhcp-494.wharton.upenn.edu:62686 ESTABLISHED TCP IT027049:1456 IT027049.massey.ac.nz:0 LISTENING TCP IT027049:1456 alb-file2.massey.ac.nz:netbios-ssn ESTABLISHED TCP IT027049:1467 IT027049.massey.ac.nz:0 LISTENING TCP IT027049:1467 itsa-campus1.massey.ac.nz:netbios-ssn ESTABLISHED TCP IT027049:1786 d226-94-36.home.cgocable.net:7091 ESTABLISHED Displays all active TCP connections and the TCP and UDP ports on which the computer is listening
TCP IT027049:1787 pcp0011009611pcs.detrtc01.mi.comcast.net:21848 ESTABLISHED TCP IT027049:1790 balticom-132-227.balticom.lv:63567 ESTABLISHED TCP IT027049:1791 24-29-117-20.nyc.rr.com:1236 ESTABLISHED TCP IT027049:8947 IT027049.massey.ac.nz:0 LISTENING UDP IT027049:microsoft-ds *:* UDP IT027049:isakmp *:* UDP IT027049:1026 *:* UDP IT027049:1027 *:* UDP IT027049:1028 *:* UDP IT027049:1046 *:* UDP IT027049:1088 *:* UDP IT027049:1177 *:* UDP IT027049:13450 *:* UDP IT027049:38037 *:* UDP IT027049:ntp *:* UDP IT027049:1187 *:* UDP IT027049:1459 *:* UDP IT027049:1718 *:* UDP IT027049:1900 *:* UDP IT027049:ntp *:* UDP IT027049:netbios-ns *:* UDP IT027049:netbios-dgm *:* UDP IT027049:1900 *:* UDP IT027049:8760 *:* UDP IT027049:62493 *:*
Testing the Client-Server Codes • Run ServerWindows.c • Compile ClientWindows.c, look for the executable. • Run ClientWindows.c from the command prompt to connect to the server: • ClientWindowslocalhost1234 • Alternatively, use IpConfig to find out what your IP address is: (e.g. 130.123.123.111), then connect to the server using: • ClientWindows130.123.123.1111234
TCP Server IPv6 ready
Winsock application startup Headers required //Ws2_32.lib #define _WIN32_WINNT 0x501 //to recognise getaddrinfo() #include <winsock2.h> #include <ws2tcpip.h> #include <stdlib.h> #include <stdio.h> //#pragma comment (lib, "Ws2_32.lib") In Windows 7, C:\Program Files\Microsoft SDKs\Windows\v7.0A\Lib\x64\Ws2_32.lib C:\Windows\System32\WS2_32.dll
Winsock application startup makefile server.exe : server.o g++ -Wl,-s -o server.exe server.o -lws2_32 server.o : server.cpp g++ -c -fpermissive -fconserve-space server.cpp Name of your program If compiling using Scite, Select Tools, then Build (or Ctrl+F7)
Winsock application startup Use a macro to define the preferred version number of the socket DLL. Use the MAKEWORD(lowbyte, highbyte)macro declared in Windef.h The high-order byte specifies the minor version number; the low-order byte specifies the major version number. #define WSVERS MAKEWORD(2,2) Ver.2.2
Winsock application startup Initialise Winsock DLL //Create a WSADATA object called wsadata. WSADATA wsadata; // Initialize the use of the Windows Sockets DLL before making other // Winsock functions calls. // This also makes certain that Winsock is supported on the system. interr; err = WSAStartup(WSVERS, &wsadata); if (err != 0) { WSACleanup(); // Tell the user that we could not find a usable WinsockDLL printf("WSAStartup failed with error: %d\n", err); }
Winsock application startup Verify the Winsock DLL version //************************************************************************************** /* Confirm that the WinSock DLL supports 2.2. */ /* Note that if the DLL supports versions greater */ /* than 2.2 in addition to 2.2, it will still return 2.2 in wVersion since that is the version we requested. */ //************************************************************************************** if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wVersion) != 2) { /* Tell the user that we could not find a usable */ /* WinSock DLL. */ printf("Could not find a usable version of Winsock.dll\n"); WSACleanup(); exit(1); } else{ printf("=================== SERVER ==================\n"); printf("The Winsock 2.2 dll was found okay\n"); }
Winsock application startup Set the socket address structure. #define DEFAULT_PORT "1234" structaddrinfo*result = NULL, *ptr = NULL, hints; intiResult; ZeroMemory(&hints, sizeof (hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; // Resolve the local address and port to be used by the server iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result); if (iResult != 0) { printf("getaddrinfo failed: %d\n", iResult); WSACleanup(); exit(1); } See sample code for a more elaborate approach.
Winsock application startup Create a socket for listening. SOCKET s; s= INVALID_SOCKET; //socket for listening // Create a SOCKET for the server to listen for client connections s= socket(result->ai_family, result->ai_socktype, result->ai_protocol); //check for errors in socket allocation if (s== INVALID_SOCKET) { printf("Error at socket(): %ld\n", WSAGetLastError()); freeaddrinfo(result); WSACleanup(); exit(1); }
Winsock application startup Bind the socket to the Server’s IP address and port number intiResult= bind(s, result->ai_addr, (int)result->ai_addrlen); if (iResult == SOCKET_ERROR) { printf("bind failed with error: %d\n", WSAGetLastError()); freeaddrinfo(result); closesocket(s); WSACleanup(); exit(1); } freeaddrinfo(result); //free the memory allocated by the getaddrinfo //function for the server's address, as it is //no longer needed
Winsock application startup Set the listen socket in motion. if (listen( s, SOMAXCONN) == SOCKET_ERROR ) { printf( "Listen failed with error: %ld\n", WSAGetLastError() ); closesocket(s); WSACleanup(); exit(1); } A special constant that allows for a maximum reasonable number of pending connections in the queue
Winsock application startup Accept a connecting client. SOCKET ns; intaddrlen= sizeof(remoteaddr); ns = INVALID_SOCKET; //Accept a client socket //ns = accept(s, NULL, NULL); ns= accept(s,(structsockaddr *)(&remoteaddr),&addrlen); if (ns == INVALID_SOCKET) { printf("accept failed: %d\n", WSAGetLastError()); closesocket(s); WSACleanup(); return 1; } else { printf("A CLIENT has been accepted.\n"); printf("\nConnected to CLIENT with IP address: %s, at port: %s\n", inet_ntoa(remoteaddr.sin_addr),portNum); } Once an incoming client is detected, a new socket is created to accept the client for connection.
Winsock application startup Communicate with the client (receive, process, send message). while (1) { n = 0; while (1) { bytes= recv(ns, &receive_buffer[n], 1, 0); if ((bytes== SOCKET_ERROR) || (bytes== 0)) break; if (receive_buffer[n] == '\n') { /*end on a LF*/ receive_buffer[n] = '\0'; break; } if (receive_buffer[n] != '\r') n++; /*ignore CRs*/ } if ((bytes== SOCKET_ERROR) || (bytes== 0)) break; sprintf(send_buffer, "client typed '%s' with %d bytes of information\r\n", receive_buffer, n); printf("\nThe client sent: %s\n",receive_buffer); //******************************************************************** bytes= send(ns, send_buffer, strlen(send_buffer), 0); if (bytes== SOCKET_ERROR) break; } Remove delimeters
Winsock application startup Shutdown connection with client int iResult = shutdown(ns, SD_SEND); if (iResult == SOCKET_ERROR) { printf("shutdown failed with error: %d\n", WSAGetLastError()); closesocket(ns); WSACleanup(); exit(1); } closesocket(ns); printf("\ndisconnected from %s\n",inet_ntoa(remoteaddr.sin_addr)); shutdown the send half of the connection since no more data will be sent
Winsock application startup Shutdown the server closesocket(s); WSACleanup(); /* call WSACleanup when done using the Winsock dll */ To release the allocated resources.
Functions and Data Structures
Winsock application startup C:\Windows\System32\WS2_32.dll #include <winsock.h> #define WSVERS MAKEWORD(2, 2) WSADATA wsadata; if (WSAStartup(WSVERS, &wsadata) != 0) { printf(“WSAStartup failed\n”); WSACleanup(); exit(1); } • The WSADATAstructure contains information about the Windows Sockets implementation. • When it has completed the use of WinSock, the application must call WSACleanup() to unregister itself from a WinSock implementation and allow the implementation to free any resources allocated on behalf of the application. Windows data types: http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751%28v=vs.85%29.aspx
Programming: Data Structures • sockaddr_in structsockaddr_in { short sin_family; u_shortsin_port; structin_addrsin_addr; char sin_zero[8]; }; sockaddr_incontains 4 fields. • sin_port - specifies aPort number • sin_addr - a 32-bitIP address • sin_zero - should be set to zeros! • sin_family - specify TCP/IP
Programming: Data Structures Internet address structure structin_addr { union { struct { u_char s_b1, s_b2, s_b3, s_b4; } S_un_b; //byte representation struct { u_shorts_w1, s_w2; } S_un_w; //word representation u_longS_addr; //long representation } S_un; //Socket - union
IP address and port number • Both are human unfriendly formats, how to we convert from and to the appropriate formats? • Short answer: • Use given conversion functions... • htons() to convert port numbers • “Host to Network Short” • Also htonl(), ntohs(), ntohl() • inet_addr() to convert IP addresses • Which format?? From X.Y.Z.T to binary • presentation to network” • Also inet_aton(), inet_pton(), inet_ntop()
Programming: Socket Commands • Creating/closing sockets socket(intprotocol_family, int transport, int zero); protocol_family is set to PF_INET for TCP/IP or AF_INET. transport is set to: • SOCK_STREAMforTCP • SOCK_DGRAMforUDP zero is set to 0 Example: s = socket(PF_INET, SOCK_STREAM, 0); closesocket(s);
Socket Commands (cont.) • making connections to a remote computer connect(SOCKET s, structsockaddr *destaddr, intaddrlen); Example: connect(s, (structsockaddr *)&sin, sizeof(sin))
Socket Commands (cont.) • Send data through a socket: send(SOCKET s, char *msg, intmsglen, int flags); s = socket (inside the socket descriptor: port and IP address...) msg = a pointer to a buffer (could be a string) msglen = the length of the buffer flags = 0 Example: send(s, sbuffer, strlen(sbuffer),0);
Socket Commands (cont.) • Receive data: intrecv(SOCKET s, char *msg, intmsglen, int flags); s = socket msg = pointer to a buffer msglen = length of the buffer flags = 0 Example: recv(s, &rbuffer[n], 1, 0); recv() causes the program to wait
Socket Commands (cont.) • Binding a port to a process(server only): int bind(SOCKET s, structsockaddr *localaddr, intaddrlen); A server has to bind port|process, so clients can access a known port for a service localaddr = pointer to a local address structure addrlen = length of localaddr Example: bind(s,(structsockaddr *)(&localaddr),sizeof(localaddr));
Socket Commands (cont.) • Listen (server only): intlisten(SOCKET s, intqueuelen); A server listens using socket s, queues requests if there is more than one. The queue limit vary (for windows up to 5). Example: listen(s, SOMAXCONN); listen() runs in the background and stays running until the socket is closed.
Socket Commands (cont.) • To accept the connection(server only): accept(SOCKET s, structsockaddr *addr, int *addrlen); Example: ns = accept(s,(structsockaddr*)(&remoteaddr),&addrlen); accept() causes the program to wait
Socket Commands (cont.) • gethostbyname(finds an IP address given a name): structhostent{ char *h_name; /*official host name*/ char **h_aliases; /*other aliases*/ short h_addrtype; /*addr type*/ short h_length; /*address length*/ char **h_addr_list; /*list of addresses*/ }*h; Example: if ((h=gethostbyname(host)) != NULL){ memcpy(&s.sin_addr, h->h_addr_list, h->h_length);} else { printf(“error\n”); exit(1); }
Simple Client/Server Codes • Read the client2.c and serv2.c codes carefully. • Note that the codes are not equipped with complete error checking. • Try to follow the logic and the usage of socket commands • Do not feel overwhelmed by the awkward syntax! • Use the debugger as a tool for understanding programs
Using the gcc debugger • Push 'debug' button • Use the various options for watching variables • Where needed use 'cmd' to start either the server or the client to communicate with the debugging session • See the demonstration....
memcpy Copies bytes between buffers. void *memcpy( void *dest, const void *src, size_t count ); Parameters: dest - New buffer. src - Buffer to copy from. count- Number of characters to copy. Return Value - value of dest. Remarks - memcpy copies count bytes from src to dest;
inet_addr converts a string containing an (Ipv4) Internet Protocol dotted address into a proper address for the in_addr structure. unsigned long inet_addr( const char FAR* cp ); Parameters cp - [in] Null-terminated character string representing a number expressed in the Internet standard "." (dotted) notation. Return Value If no error occurs, this function returns an unsigned long value containing a suitable binary representation of the Internet address given. If the string in the cp parameter does not contain a legitimate Internet address, for example if a portion of an a.b.c.d address exceeds 255, then inet_addr returns the value INADDR_NONE.
inet_ntoa This function converts an (Ipv4) Internet network address into a string in Internet standard dotted format. char FAR* inet_ntoa( struct in_addr in ); Parameters in - [in] Structure that represents an Internet host address. Return Value If no error occurs, this function returns a character pointer to a static buffer containing the text address in standard "." notation. If an error occurs, it returns NULL.
ntohs The ntohs function converts a u_short from TCP/IP network byte order to host byte order (which is little-endian on Intel processors). u_short ntohs( u_short netshort ); To view the Port number in human-readable form, e.g. Port 1444. this is used after the accept() function is called. Parameters netshort [in] 16-bit number in TCP/IP network byte order. Return Value The ntohs function returns the value in host byte order. If the netshort parameter was already in host byte order, then no operation is performed. Remarks The ntohs function takes a 16-bit number in TCP/IP network byte order and returns a 16-bit number in host byte order.