CS作业代写 IT043429.massey.ac.nz //host name assigned to my machine back – cscodehelp代写
IPv6 ready
Cross-platform
Socket API (C Language)
For code compatibility, as much as possible, we will be using data types and functions that are compatible to both Windows and Unix-based OS (i.e. Linux, MacOS, etc.)
Copyright By cscodehelp代写 加微信 cscodehelp
IPv6 ready
The following code snippets were simplified for brevity of discussions. Please see the complete sample codes for a more elaborate approach on handling errors.
Winsock application startup
Include the headers required
#include
C:WindowsSystem32WS2_32.dll
Winsock application startup
WS2_32.dll
Name of your program
: server.o
g++ -o server.exe server.o -lws2_32 -o server.exe
server.exe
server.o : server.cpp
g++ -c –O3 –Wall server.cpp tab optimise
Turn on all optional warnings
If compiling on the command-line, type make
If compiling using the SublimeText IDE,
Select Tools, then Build (or Ctrl+Shift+B, then select the Build type preferred)
Compiler options:
https://gcc.gnu.org/onlinedocs/gcc/Option-Index.html#Option-Index
Initialise socket library WS2_32.dll
Winsock application startup
Use a macro to define the preferred version number of the socket DLL (Ws2_32.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) Low-order (major
high-order (minor version)
The current version of the Windows Sockets specification is version 2.2.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms742213(v=vs.85).aspx
Winsock application startup
//Create a WSADATA object called wsadata.
WSADATA wsadata;
// Initialize the use of the Windows Sockets DLL before making other
• The WSADATA structure contains information about the Windows Sockets implementation.
// Winsock functions calls.
// This also makes certain that Winsock is supported on the system.
err = WSAStartup(WSVERS, &wsadata);
if (err != 0) { WSACleanup();
• free any resources allocated on behalf of the application.
// Tell the user that we could not find a usable WinsockDLL
printf(“WSAStartup failed with error: %d
”, err);
exit(1); }
Winsock application startup
//Create a WSADATA object called wsadata.
WSADATA wsadata;
// Initialize the use of the Windows Sockets DLL before making other
• The WSADATA structure contains information about the Windows Sockets implementation.
// Winsock functions calls.
// This also makes certain that Winsock is supported on the system.
err = WSAStartup(WSVERS, &wsadata);
if (err != 0) { WSACleanup();
• free any resources allocated on behalf of the application.
// Tell the user that we could not find a usable WinsockDLL
printf(“WSAStartup failed with error: %d
”, err);
exit(1); }
Winsock application startup
Verify that the Winsock DLL supports the latest version, 2.2.
//**************************************************************************************
/* 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
”); WSACleanup();
exit(1); }
printf(“=================== SERVER ==================
”); printf(“The Winsock 2.2 dll was found okay.
”);
Winsock application startup
Verify that the Winsock DLL supports the latest version, 2.2.
//**************************************************************************************
/* 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
”); WSACleanup();
exit(1); }
printf(“=================== SERVER ==================
”); printf(“The Winsock 2.2 dll was found okay.
”);
Preparing the Server to listen and accept
A server needs an IP address and a listening socket (identified by its port number)
Listening Socket
What happens if we only know the hostname/domain name of a server, but not its IP address?
PorSt number Hostname and IP address
We need to utilise the services of the DNS infrastructure! How is this done in a program?
e.g. www.google.co.nz //hostname
IT043429.massey.ac.nz //host name assigned to my machine back
Preparing the Server to listen and accept
Resolve the local address and port to be used by the server
can query the DNS infrastructure
WSAStartup()
getaddrinfo(hostname, portnum, &hints, &result)
s = socket()
Socket type
Examine how the output of one function is used by the s is a socket for listening (used by the server).
Winsock application startup
int getaddrinfo(const char *hostname, const char *service, Set the socket address structure.
const struct addrinfo *hints, struct addrinfo **result);
#define DEFAULT_PORT “1234” struct addrinfo *result = NULL, hints; int iResult;
//ZeroMemory(&hints, sizeof (hints)); //alternatively, for Windows only memset(&hints, 0, sizeof(struct addrinfo));
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
”, iResult);
WSACleanup();
exit(1); }
Winsock application startup
int getaddrinfo(const char *hostname, const char *service, Set the socket address structure.
const struct addrinfo *hints, struct addrinfo **result);
#define DEFAULT_PORT “1234” struct addrinfo *result = NULL, hints; int iResult;
//ZeroMemory(&hints, sizeof (hints)); //alternatively, for Windows only memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET; //or set to AF_INET6 for IPv6 addresssing hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; //socket for listening
// 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
”, iResult);
WSACleanup();
exit(1); }
See sample code for a more elaborate approach.
Syntax: getaddrinfo()
int getaddrinfo(const char *hostname, const char *service,
for converting domain name system (DNS) hostnames and IP addresses between their human-readable text representations and structured binary formats for the operating system’s networking API.
const struct addrinfo *hints, struct addrinfo **result);
struct addrinfo {
int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST, .. */
int ai_family; /* Host address type, i.e. AF_xxx */
int ai_socktype; /* SOCK_xxx */
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
socklen_t ai_addrlen; /* length of ai_addr, in bytes */
char *ai_canonname; /* official domain name/canonical name for host*/
struct sockaddr *ai_addr; /* binary address */
struct addrinfo *ai_next; /* other entries for host: next structure in linked list */
http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/posix/getaddrinfo.c;hb=HEAD#l2061
Functions for retrieving host entries from DNS
• getaddrinfo(): query key is a DNS host name
loopback all refers to the same loop back address localhost
Machine-specific
• getnameinfo(): query key is an IP address in structured binary format
0:0:0:0:0:0:0:1
::1 fd94:fe22:9f1d:e700:d2af:8f09:b1cc:834e
IPv6, loopback
Preparing the Server to listen and accept
Create a socket for listening.
WSAStartup()
getaddrinfo(hostname, portnum, &hints, &result)
s = socket()
Socket type
socket() requires a specific data structure to contain all the socket properties that we want to create.
Winsock application startup
Create a socket for listening.
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(): %d
”, WSAGetLastError());
freeaddrinfo(result); WSACleanup(); exit(1);
Winsock application startup
Create a socket for listening.
s = INVALID_SOCKET;
// 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(): %d
”, WSAGetLastError()); freeaddrinfo(result);
WSACleanup();
Syntax: socket()
Creating/closing sockets socket(int address_family, int type, int protocol);
address_family: PF_INET, AF_INET, AF_INET6, AF_BTH, AF_IRDA, AF_UNSPEC, etc.
Type is set to:
Protocol is set to:
SOCK_STREAM for TCP SOCK_DGRAM for UDP SOCK_RAW, etc.
IPPROTO_TCP for TCP IPPROTO_UDP for UDP IPPROTO_ICMP, etc.
Address_information_family
s = socket(result->ai_family, result->ai_socktype, result->ai_protocol); …
s = socket(PF_INET, SOCK_STREAM, 0); closesocket(s);
Preparing the Server to listen and accept
Bind the socket to the Server’s IP address and port number.
WSAStartup() getaddrinfo()
s = socket()
Socket type
Winsock application startup
Bind the socket to the Server’s IP address and port number
int iResult = bind(s, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf(“bind failed with error: %d
”, WSAGetLastError()); freeaddrinfo(result);
closesocket(s);
WSACleanup();
freeaddrinfo(result); //free the memory allocated by getaddrinfo() //for the server’s address, as it is
//no longer needed
Winsock application startup
Bind the socket to the Server’s IP address and port number
int iResult = bind(s, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf(“bind failed with error: %d
”, WSAGetLastError()); freeaddrinfo(result);
closesocket(s);
WSACleanup();
freeaddrinfo(result); //free the memory allocated by getaddrinfo() //for the server’s address, as it is
//no longer needed
Syntax: bind()
Binding a port to a process (server only):
int bind(SOCKET s, struct sockaddr *localaddr, int addrlen);
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
r = bind(s,(struct sockaddr *)(&localaddr),sizeof(localaddr)); int result = bind(s, result->ai_addr, (int)result->ai_addrlen);
Preparing the Server to listen and accept
Set the listen socket in motion
WSAStartup() getaddrinfo()
s = socket()
listen(s, … )
Socket type
A special constant that allows for a maximum reasonable number of pending connections in the queue
Winsock application startup
Set the listen socket in motion.
if (listen( s, SOMAXCONN ) == SOCKET_ERROR ) {
printf( “Listen failed with error: %d
”, WSAGetLastError() ); closesocket(s);
WSACleanup();
listen() runs in the background and stays running until the socket is closed.
More info about the listen function
Listen (server only):
int listen(SOCKET s, int queuelen);
A server listens using socket s, queues requests if there is more than one.
The queue limit vary (for windows up to 5).
listen(s, SOMAXCONN);
listen() runs in the background and stays running until the socket is closed.
Preparing the Server to listen and accept
Accept a connecting client
WSAStartup() getaddrinfo()
s = socket()
bind(s, ) listen(s, … )
ns = accept(s, … ) Communicate with client
put inside a loop
Socket type
accept() causes the program to wait
Winsock application startup
Accept a connecting client.
SOCKET ns;
int addrlen = sizeof(remoteaddr);
ns = INVALID_SOCKET;
//Accept a client socket
ns = accept(s,(struct sockaddr *)(&remoteaddr),&addrlen); if (ns == INVALID_SOCKET) {
printf(“accept failed: %d
”, WSAGetLastError()); closesocket(s);
WSACleanup();
printf(“A CLIENT has been accepted.
”);
printf(“
Connected to CLIENT with IP address: %s, at port: %d
”, inet_ntoa(remoteaddr.sin_addr), ntohs(remoteaddr.sin_port));
Winsock application startup
Accept a connecting client.
SOCKET ns;
int addrlen = sizeof(remoteaddr);
ns = INVALID_SOCKET;
//Accept a client socket
ns = accept(s,(struct sockaddr *)(&remoteaddr),&addrlen); if (ns == INVALID_SOCKET) {
printf(“accept failed: %d
”, WSAGetLastError());
closesocket(s); WSACleanup(); exit(1);
Once an incoming client is detected, a new socket is created to accept the client for connection.
printf(“A CLIENT has been accepted.
”);
Only works in IPv4! We will see an alternative to these
Winsock application startup
Accept a connecting client.
SOCKET ns;
int addrlen = sizeof(remoteaddr);
ns = INVALID_SOCKET;
//Accept a client socket
ns = accept(s,(struct sockaddr *)(&remoteaddr),&addrlen); if (ns == INVALID_SOCKET) {
printf(“accept failed: %d
”, WSAGetLastError());
closesocket(s); WSACleanup(); exit(1);
Once an incoming client is detected, a new socket is created to accept the client for connection.
printf(“A CLIENT has been accepted.
”);
printf(“
Connected to CLIENT with IP address: %s, at port: %d
”, inet_ntoa(remoteaddr.sin_addr), ntohs(remoteaddr.sin_port));
functions, to make the codes IPv6-compatible
More info on accept()
To accept the connection (server only): accept(SOCKET s, struct sockaddr *addr, int *addrlen);
//struct sockaddr_in clientAddress; //IPV4
struct sockaddr_storage clientAddress; //both IPV4 and IPV6-compliant
ns = accept(s,NULL,NULL);
ns = accept(s,(struct sockaddr*)(& clientAddress),&addrlen);
accept() causes the program to wait
http://msdn.microsoft.com/en-us/library/windows/desktop/ms737526%28v=vs.85%29.aspx back 32
Client-Server Communication Begins
TCP connection is now established.
WSAStartup() getaddrinfo()
s = socket()
listen(s, … )
ns = accept(s, … )
Socket type
Connection between client & server is now established.
getnameinfo()
Extracting human-readable IP address/host name and port number
struct sockaddr_storage clientAddress; //IPV6-compatible char clientHost[NI_MAXHOST]; //IP address
char clientService[NI_MAXSERV]; //port address
ns = accept(s,(struct sockaddr *)(&clientAddress),&addrlen); …
memset(clientHost, 0, sizeof(clientHost)); memset(clientService, 0, sizeof(clientService));
Not readily human- readable or printable.
getnameinfo((struct sockaddr *)&clientAddress, addrlen, clientHost, sizeof(clientHost),
clientService, sizeof(clientService), NI_NUMERICHOST);
printf(“
Connected to <<
”, clientHost, clientService);
getnameinfo()
Extracting human-readable IP address/host name and port number
struct sockaddr_storage clientAddress; //IPV6-compatible char clientHost[NI_MAXHOST]; //IP address
char clientService[NI_MAXSERV]; //port address
ns = accept(s,(struct sockaddr *)(&clientAddress),&addrlen); …
memset(clientHost, 0, sizeof(clientHost)); memset(clientService, 0, sizeof(clientService));
Not readily human- readable or printable.
getnameinfo((struct sockaddr *)&clientAddress, addrlen, clientHost, sizeof(clientHost),
extracts IP address of client
clientService, sizeof(clientService), NI_NUMERICHOST);
printf(“
Connected to <<
”, clientHost, clientService);
Syntax: getnameinfo()
Extracting human-readable IP address/host name and port number
int getnameinfo( const struct sockaddr *saddr, socklen_t saddr_length, char *host, DWORD hostlen,
char *serv, DWORD
servlen, int flags );
getnameinfo((struct sockaddr *)&clientAddress, addrlen, clientHost, sizeof(clientHost),
A 32-bit unsigned integer.
The range is 0 through 4294967295 decimal. This type is declared in IntSafe.h as follows: typedef unsigned long DWORD;
extracts IP address of NI_NUMERICHOST); client
clientService, sizeof(clientService),
printf(“
Connected to <<
”,clientHost, clientService);
Communication Session with a Client
Server-side
Now that the connection has been established, let’s try to answer the following questions:
How a packet is retrieved and filtered?
What happens when a client disconnects without saying good bye first?
while (1) { n = 0;
Winsock application startup
Server: communicate with the client (receive, process, send message).
while (1) {
bytes = recv(ns, &receive_buffer[n], 1, 0);
size may vary
if ((bytes == SOCKET_ERROR) || (bytes == 0)) break;
if (receive_buffer[n] == ‘
’) { /*end on a LF*/ Receive message, then filter it.
message
delimeter
receive_buffer [n] = ‘