IPv6 ready C/C++ Language
Goal: learn how to build client/server applications that communicate using UDP sockets
Download the udp server & client codes for this lecture
Copyright By PowCoder代写 加微信 powcoder
Socket programming with UDP
UDP is a no-frills connectionless protocol
no handshaking required (no connection establishment delay)
No logical connection between client and server
Simple protocol: does not keep state information at sender and receiver No congestion control: UDP does not throttle down its sending rate
suitable for applications that are loss-tolerant and rate sensitive used by DNS, live streaming and online games
UDP: transmitted data may be received out of order, or lost
offers only a best-effort transport service
It is up to the application process to implement any required service (i.e. reliable data transfer, error-checking, etc.)
Application viewpoint:
UDP provides unreliable transfer of groups of bytes (“datagrams”) between client and server 2
Socket programming with UDP
Similar to an ordinary postal mail, a UDP packet arriving at a destination host comes with destination and source addresses.
Socket programming with UDP UDP:
Sender: explicitly attaches destination port number and IP address to each packet. Typically, OS attaches the source address.
Receiver: must extract IP address, port of sender from received packet
IP datagram
UDP datagram
Source Port: 1200 Destination Port: 33434
Message…
Source IP: 47.120.100.6 Destination IP: 130.123.245.1
Client/server socket application
Let’ examine the details of UDP socket programming following a simple client-server protocol.
1. Client reads a line of characters (data) from its keyboard. If input is a single-dot (.), exit; otherwise, send data to the server.
2. Theserverreceivesthedataandperformssomeoperation on it.
3. Theserversendsthemodifieddatatotheclient.
4. Theclientreceivesthemodifieddataanddisplaystheline
on its screen
5. GobacktoStep1.
Application 2-5
Simple Client/server application: UDP Use AF_INET6 for IPv6
Server (running on hostid) create socket,
connections
port= x. serverSocket =
create socket, clientSocket =
socket(AF_INET, SOCK_DGRAM,0) Loop
Create datagram with server (hostid, port=x), send datagram via
receive datagram from serverSocket
clientSocket
send reply to serverSocket
specifying client address, port number
receive datagram from clientSocket
Close serverSocket (network admin controlled)
Close clientSocket
socket(AF_INET, SOCK_DGRAM,0)
Application 2-6
Download the sample UDP server & UDP client codes from our Stream website
Test the UDP Client-Server Codes Before you compile the codes, make sure that both client and server are
using the same addressing scheme. Set both to use either IPv4 or IPv6 • hints.ai_family = AF_INET; //for IPv4
• hints.ai_family = AF_INET6; //for IPv6
Compile the UDP server and client programs.
Run the server: Server_UDP 1234
Run Client_UDP.exe from the command prompt to connect to the server:
Client_UDP localhost 1234
or Client_UDP 127.0.0.1 1234 //IPv4 only
Alternatively, use the ipconfig command to find out what is the server’s IP address is: (e.g. 130.123.123.111), then connect to the server using:
• Client_UDP 130.123.123.111 1234
Note: In this demo, the programs have been set to restrict the number of characters that can be sent/received. Max of 50 characters only.
Test the UDP Client-Server Codes
Test the UDP Client-Server Codes Observations
In the simple demo, where a UDP server echoes back the received message (simply converts them in upper case), a single-threaded UDP server is able to communicate quickly with two “simultaneous” UDP clients.
This is because the server is not tied up with any connections. UDP is a connectionless protocol.
Each UDP datagram received by the server contains a sender’s return address (IP address and port number). Therefore, a server may receive multiple datagrams coming from multiple senders.
In comparison, a TCP server can only communicate simultaneously with multiple TCP clients via multithreading.
TCP SERVER & CLIENT s = socket
s = socket bind
loop “forever” {
ns = accept /* by creating newsocket */ /* communicate with client*/
loop until done
send(s, …)
recv(s, …) }
recv(ns, &receive_buffer[n], 1, 0); send(ns, send_buffer,
closesocket(s)
strlen(send_buffer), 0);
closesocket(ns) //newsocket
/* communicate with server*/
loop until done {
syntax: udp_server server_port_num WSAStartup()
getaddrinfo()
s = socket()
Socket type address
UDP Server
Communication session with client(socket)
closesocket(s) WSACleanup()
getaddrinfo()
s = socket()
UDP Client
syntax: udp_client server_ip_address server_port_num WSAStartup()
Socket type
Server’s address and port number
Communication session with server(socket, server’s address info)
closesocket(s) WSACleanup()
implemented in a loop
UDP server-client interaction
SERVER CLIENT
udp_server server_port_num udp_client server_ip_address server_port_num
getaddrinfo(…,&result) s = socket
loop “forever”
getaddrinfo(…,&result) s = socket
loop until done
//get user command…
//generate content of send_buffer
UDP SERVER & CLIENT
blocks and waits for data to arrive
bytes = recvfrom(s, receive_buffer, sizeof(receive_buffer), 0,
(struct sockaddr*)(&remoteaddr),
bytes = sendto(s, send_buffer, strlen(send_buffer),0,
&addrlen);
getnameinfo( ) //extract sender’s identity
result->ai_addr,
//filter receive_buffer…
result->ai_addrlen ); bytes = recvfrom(s,
process_cmd(receive_buffer) //command bytes = sendto(s, send_buffer,
receive_buffer, sizeof(receive_buffer), 0,
strlen(send_buffer),0,
(struct sockaddr *)(&remoteaddr), sizeof(remoteaddr) );
(struct sockaddr *)(&remoteaddr), &addrlen );
}} closesocket(s) closesocket(s)
//process reply…
The following codes were simplified for brevity of discussions. Socket initialisation codes that were discussed previously when we covered TCP socket programming are only discussed briefly here.
Please see the sample codes for the complete implementation.
#elif defined _WIN32
Cross-platform
#if defined __unix__ || defined __APPLE__
#include
#include
#include
#include
#include
#include
#include
#include
Required only by Windows
//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\n”, err);
exit(1); }
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\n”); WSACleanup();
exit(1); }
printf(“=================== SERVER ==================\n”); printf(“The Winsock 2.2 dll was found okay.\n”);
struct addrinfo *result = NULL; struct addrinfo hints;
int iResult;
memset(&hints, 0, sizeof(struct addrinfo));
UDP Server
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM; // Datagram socket hints.ai_flags = AI_PASSIVE; // For wildcard IP address hints.ai_protocol = IPPROTO_UDP;
iResult = getaddrinfo(NULL, argv[1], &hints, &result);
s = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
UDP Server
// bind the socket to the local address of the machine and port number
iResult = bind( s, result->ai_addr, (int)result->ai_addrlen);
freeaddrinfo(result); //free the memory allocated by the getaddrinfo //function for the server’s address, as it is
//no longer needed
Data structures
#define BUFFER_SIZE 200
char clientHost[NI_MAXHOST]; char clientService[NI_MAXSERV];
UDP Server
char send_buffer[BUFFER_SIZE],receive_buffer[BUFFER_SIZE];
int bytes;
Ws2tcpip.h
/* getnameinfo constants */ #define NI_MAXHOST 1025 #define NI_MAXSERV 32
UDP Server Receiving a datagram: recvfrom()
struct sockaddr_storage clientAddress; //allows ipv4 and ipv6 socklen_t addrlen;
char portNum[NI_MAXSERV];
addrlen = sizeof(clientAddress); //IPv4 & IPv6-compliant
while(1) { //main loop
printf(“the <<
//receive datagram and store the source address.
bytes = recvfrom(s, receive_buffer, sizeof(receive_buffer), 0, (struct sockaddr*)&clientAddress, &addrlen);
if(bytes < 0){ continue;
blocks and waits for data to arrive
UDP Server Extracting the Sender’s identity: getnameinfo()
//******************************************************************** //IDENTIFY UDP client's IP address and port number. //********************************************************************
memset(clientHost, 0, sizeof(clientHost)); memset(clientService, 0, sizeof(clientService)); getnameinfo((struct sockaddr *)&clientAddress, addrlen,
clientHost, sizeof(clientHost), clientService, sizeof(clientService), NI_NUMERICHOST);
printf("\nReceived a packet of size %d bytes from <<
UDP Server: Communication session
while (1) { //main loop
bytes = recvfrom(s, receive_buffer, sizeof(receive_buffer), 0, (struct sockaddr*)&clientAddress,
&addrlen);
getnameinfo(…) //extract human-readable client IP address and port number
while (n < bytes){//EXTRACT one command, delimited by \r\n
Receive message, then extract sender’s address details
if (bytes < 0) break;
if (receive_buffer[n] == '\n') { /*end on a LF*/
receive_buffer[n] = '\0';
removal of message delimeters (\r\n)
if (receive_buffer[n] == '\r'){ /*ignore CRs*/ receive_buffer[n] = '\0';
memset(send_buffer, 0, sizeof(send_buffer)); sprintf(send_buffer,"%s %s", "the client typed: ", receive_buffer); addrlen=sizeof(clientAddress);
bytes = sendto(s, send_buffer, strlen(send_buffer), 0,
Reply message
} //end – main loop closesocket(s); WSACleanup();
download udp server & client codes to see
(struct sockaddr *)&clientAddress, addrlen);
the complete codes 26
WSAStartup() getaddrinfo()
Recall the UDP client’s pseudocode (shown here as a guide for the next discussion)
s = socket()
UDP Client
syntax: udp_client server_ip_address server_port_num
Socket type
Server’s address and port number
Communication session with server(socket, server’s address info)
closesocket(s) WSACleanup()
implemented in a loop
Client UDP syntax: udp_client server_ip_address server_port_num
clientUDP.cpp
struct addrinfo *result=NULL, hints; int iResult;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ //hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ hints.ai_protocol = IPPROTO_UDP;
hints.ai_canonname = NULL; //full canonical hostname hints.ai_addr = NULL; //struct sockaddr_in or .._in6 hints.ai_next = NULL; //linked list, next node
Only for servers
//Server’s IP address: get it from argv[1]
//Server’s Port number: get it from argv[2]
if (argc == 3){ //if there are 3 parameters passed to the argv[] array.
sprintf(portNum,"%s", argv[2]);
iResult = getaddrinfo(argv[1], portNum, &hints, &result); cout << "connecting to " << argv[1] << endl;
printf("USAGE: client_udp IP-address [port]\n"); //missing IP address
printf("Using default settings, localhost, Port:1234\n"); sprintf(portNum,"%s", DEFAULT_PORT);
iResult = getaddrinfo("localhost", portNum, &hints, &result);
// iResult – result from getaddrinfo()
clientUDP.cpp
if (iResult != 0) {
printf("getaddrinfo failed: %d\n", iResult);
freeaddrinfo(result); WSACleanup(); return 1;
s = INVALID_SOCKET; //socket for listening
Client UDP
// 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\n”, WSAGetLastError()); freeaddrinfo(result);
WSACleanup();
} 29 printf(“\nSOCKET created.\n”);
memset(send_buffer, 0, sizeof(send_buffer));//clean up printf(“\nwaiting for user input…\n”); get_keyboard(send_buffer);
struct sockaddr_storage serverAddress;
clientUDP.cpp
socklen_t addrlen = sizeof(serverAddress);
while (strncmp(send_buffer,”.”,1) != 0) { //SEND
Client UDP
bytes = sendto(s, send_buffer, strlen(send_buffer),0, (result->ai_addr), result->ai_addrlen);
memset(receive_buffer, 0, sizeof(receive_buffer)); //clean up bytes = recvfrom(s, receive_buffer, sizeof(receive_buffer), 0,
(struct sockaddr*)(&serverAddress), &addrlen );
process_received_message(receive_buffer); //user-defined memset(send_buffer, 0, sizeof(send_buffer)); //clean up get_keyboard(send_buffer); //get user input
freeaddrinfo(result); closesocket(s); //close(s); //in Linux WSACleanup();
#define BUFFER_SIZE 200
#define SEGMENT_SIZE 80 //////////////////////////////////////////////////////////////////////////////////////////////////////////////// void get_keyboard(char * send_buffer) {
clientUDP.cpp
if(fgets(send_buffer,SEGMENT_SIZE, stdin) ==NULL){ printf(“fgets() error!\n”);
• Read input from the keyboard
send_buffer[strlen(send_buffer)-1]=’\0′;//strip ‘\n’ strcat(send_buffer,”\r\n”);
printf(“Message length: %d \n”,(int)strlen(send_buffer));
• filter out the ‘\n’ due to fgets()
Client UDP
• lastly, append ‘\r\n\0’
e.g. hello\r\n\0
Send data through a socket:
int sendto(SOCKET s, const char *msg, int msglen, int flags, const struct sockaddr *to, int tolen);
PARAMETERS
s = socket descriptor
msg = a pointer to a buffer
msglen = the length of the buffer
flags = 0 (we will set it to zero for our applications) to=structure of address with the IP / port # tolen=length of the structure
Examples: struct addrinfo *result;
bytes=sendto(s, send_buffer, strlen(send_buffer),0, result->ai_addr, result->ai_addrlen); bytes=sendto(s, send_buffer, strlen(send_buffer), 0,
(struct sockaddr *)&clientAddress, addrlen);
Send data through a socket:
int sendto(SOCKET s, const char *msg, int msglen, int flags, const struct sockaddr *to, int tolen);
Examples: struct addrinfo *result;
bytes=sendto(s, send_buffer, strlen(send_buffer),0, result->ai_addr, result->ai_addrlen); bytes=sendto(s, send_buffer, strlen(send_buffer), 0,
(struct sockaddr *)&clientAddress, addrlen);
Returns number of bytes sent.
If an error occurs during sending, SOCKET_ERROR is returned.
PARAMETERS
recvfrom()
Receive a datagram and stores the source address. int recvfrom(SOCKET s, char *msg, int msglen,
int flags, struct sockaddr *from, int *fromlen)
s = socket (inside the socket descriptor: port and IP address…) msg = a pointer to a buffer
msglen = the capacity of the buffer in bytes
from =(optional) structure of address with the IP / port # fromlen=(optional) length of the structure
Example: struct sockaddr_storage remoteaddr;
bytes = recvfrom(s, receive_buffer, sizeof(receive_buffer), 0, (struct sockaddr*)(&remoteaddr), &addrlen );
recvfrom()
Receive a datagram and stores the source address. int recvfrom(SOCKET s, char *msg, int msglen,
int flags, struct sockaddr *from, int *fromlen) blocks and waits for data
Example: struct sockaddr_storage remoteaddr;
bytes = recvfrom(s, receive_buffer, sizeof(receive_buffer), 0,
(struct sockaddr*)(&remoteaddr), &addrlen );
Returns number of bytes received.
If bytes is equal to zero, then the peer gracefully shutdown; otherwise, an error is returned (SOCKET_ERROR).
程序代写 CS代考 加微信: powcoder QQ: 1823890830 Email: powcoder@163.com