Java程序辅导

C C++ Java Python Processing编程在线培训 程序编写 软件开发 视频讲解

客服在线QQ:2653320439 微信:ittutor Email:itutor@qq.com
wx: cjtutor
QQ: 2653320439
UDP Socket Programming UDP Socket Programming An Introduction with Examples in C Prof. David Bernstein James Madison University Computer Science Department bernstdh@jmu.edu Review UDP: Not connection-orieneted Message-oriented Unreliabale Internet Programming Basics: Byte order Addresses and ports UDP Programming Both Parties: socket() The Receiving Party: bind() recvfrom() The Sending Party: sendto() Creating a Socket: socket() int socket(int domain, int type, int protocol) Purpose: Create a socket Details: domain AF_INET or AF_INET6 for IP type SOCK_DGRAM for UDP protocol 0 for UDP over IP Return The file descriptor on success; -1 on error #include Setting-Up for Receiving Conceptually: The socket can be bound to any IP address on the host The socket must be bound to a particular port so that it can be "advertised" Initializing the sockaddr: struct sockaddr_in address; memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_port = htons(WELL_KNOWN_PORT); // For this service address.sin_addr.s_addr = htonl(INADDR_ANY); Binding to an Address and/or Port: bind() int bind(int fd, const struct sockaddr *addr, socklen_t addrlen) Purpose: Associate a socket with a particular address and/or port Details: fd The file descriptor of a socket addr The address/port to bind to addrlen The length of the address Return 0 on success; -1 on error #include Receiving a Datagram: recvfrom() ssize_t recvfrom(int fd, void *buffer, size_t buflen, int flags, struct sockaddr *src_addr, socklen_t *addrlen) Purpose: Receive a UDP datagram Details: fd The file descriptor of the UDP socket buffer The buffer to fill with the datagram's payload length The length of the buffer flags Flags (often 0) src_addr The address the datagram was sent from addrlen The length of the source's address Return The number of bytes received on success; -1 on error #include A Simple Sequential Text "Receiver" unixexamples/udp/weather_recorder.c #include // For byte order conversions #include // For memset() #include #include #include "weather.h" int main(void) { char buffer[STATION_SIZE+TEMPERATURE_SIZE]; int fd, keep_going; struct sockaddr_in address; // Create a IP4/UDP socket fd = socket(AF_INET, SOCK_DGRAM, 0); // Initialize the address (of this host) memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_port = htons(TEMPERATURE_PORT); address.sin_addr.s_addr = htonl(INADDR_ANY); // In case the host has multiple // Bind the socket to the address bind(fd, (struct sockaddr *)&address, sizeof(struct sockaddr)); keep_going = 1; while (keep_going) { // Receive the message (we don't care about the address of the sender) recvfrom(fd, buffer, STATION_SIZE+TEMPERATURE_SIZE, 0, NULL, NULL) ; if (buffer[3] == '!') { keep_going = 0; } else { write(STDOUT_FILENO, "Report from ", 12); write(STDOUT_FILENO, buffer, STATION_SIZE); write(STDOUT_FILENO, ": ", 2); write(STDOUT_FILENO, buffer+STATION_SIZE, TEMPERATURE_SIZE); write(STDOUT_FILENO, "\n\n", 2); } } close(fd); } A Simple Sequential Text "Receiver" (cont.) A Conceptual Question: Is this "receiver" a client, a server, or neither? An Answer and Explanation: Because its role is to wait for and respond to a request (i.e., to record data), it is a server Setting-Up for Sending Conceptually: The datagram can be sent from any address/port so the socket needn't be bound The datagram must be sent to a particular address/port (so that information will have to be passed to the function that does the sending) Initializing the Destination sockaddr: struct sockaddr_in destination; memset(&destination, 0, sizeof(struct sockaddr_in)); destination.sin_family = AF_INET; inet_pton(AF_INET, RECEIVER_ADDRESS, &(destination.sin_addr)); destination.sin_port = htons(RECEIVER_PORT); Sending a Datagram: sendto() ssize_t sendto(int fd, const void *buffer, size_t buflen, int flags, const struct sockaddr *dest_addr, socklen_t *addrlen) Purpose: Send a UDP datagram to a particular address and port Details: fd The file descriptor of the UDP socket buffer The datagram's payload length The length of the payload flags Flags (often 0) dest_addr The address to send the datagram to addrlen The length of the destination address Return The number of bytes sent on success; -1 on error #include A Simple Text "Sender" unixexamples/udp/weather_station.c #include // For byte order conversions #include // For memset() #include #include #include "weather.h" int main(int argc, char *argv[]) { char buffer[STATION_SIZE+TEMPERATURE_SIZE]; char station[] = "JMU"; char temperature[TEMPERATURE_SIZE+1]; int fd, keep_going; ssize_t input_length; struct sockaddr_in destination; if (argc > 1) strncpy(station, argv[1], STATION_SIZE); // Create a IP4/UDP socket fd = socket(AF_INET, SOCK_DGRAM, 0); // Initialize the address of the receiver memset(&destination, 0, sizeof(struct sockaddr_in)); destination.sin_family = AF_INET; inet_pton(AF_INET, "134.126.125.234", &(destination.sin_addr)); destination.sin_port = htons(TEMPERATURE_PORT); keep_going = 1; while (keep_going) { write(STDOUT_FILENO, "Temperature (or [Enter] to QUIT): ", 35); // Clear the outgoing payload memset(buffer, 0, STATION_SIZE+TEMPERATURE_SIZE); // Populate the outgoing payload strncpy(buffer, station, 3); input_length = read(STDIN_FILENO, temperature, TEMPERATURE_SIZE+1); if (input_length > 1) { strncpy(buffer+3, temperature, input_length-1); } else { strncpy(buffer+3, "!!!!!", 5); keep_going = 0; } // Send the datagram sendto(fd, buffer, STATION_SIZE+TEMPERATURE_SIZE, 0, (struct sockaddr *)&destination, sizeof(destination)) ; } close(fd); } Sending/Receiving and Clients/Servers A Conceptuial Question: Are all "senders" clients and all "receivers" servers? An Answer and Explanation: No! In fact, both clients and servers often both send and receive. A Server that Receives and Sends An Observation: In the example above, all communication is one-way A Different Example: The client requests a forecast for a particular location (using UDP) and the server responds (again using UDP) A Server that Receives and Sends (cont.) unixexamples/udp/forecast_server.c #include #include #include #include #include #include #include "weather.h" int main(void) { char in[STATION_SIZE], out[TEMPERATURE_SIZE]; int fd; struct sockaddr_in address, client_address; socklen_t client_length = sizeof(struct sockaddr); // Create an IP4/UDP socket fd = socket(AF_INET, SOCK_DGRAM, 0); // Initialize the address of this host memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_port = htons(FORECAST_PORT); address.sin_addr.s_addr = htonl(INADDR_ANY); // In case the host has multiple // Bind the socket to the address bind(fd, (struct sockaddr *)&address, sizeof(struct sockaddr)); // Process requests while (1) { // Receive the request recvfrom(fd, in, STATION_SIZE, 0, (struct sockaddr *)&client_address, &client_length); // Send the response memset(&out, 0, TEMPERATURE_SIZE); sprintf(out, "%5.1f", forecast_for(in)); sendto(fd, out, TEMPERATURE_SIZE, 0, (struct sockaddr *)&client_address, client_length); } close(fd); } A Client that Sends and Receives unixexamples/udp/forecast_client.c #include #include #include #include #include "weather.h" int main(int argc, char *argv[]) { char in[TEMPERATURE_SIZE]; char out[] = "JMU"; int fd; struct sockaddr_in server_address; if (argc > 1) strncpy(out, argv[1], STATION_SIZE); // Create an IP4/UDP socket fd = socket(AF_INET, SOCK_DGRAM, 0); // Initialize the address of the server memset(&server_address, 0, sizeof(struct sockaddr_in)); server_address.sin_family = AF_INET; inet_pton(AF_INET, "134.126.125.234", &(server_address.sin_addr)); server_address.sin_port = htons(FORECAST_PORT); // Send the request sendto(fd, out, STATION_SIZE, 0, (struct sockaddr *)&server_address, sizeof(server_address)) ; // Receive the response recvfrom(fd, in, TEMPERATURE_SIZE, 0, NULL, NULL); // Display the respons write(STDOUT_FILENO, "Forecast: ", 10); write(STDOUT_FILENO, in, TEMPERATURE_SIZE); write(STDOUT_FILENO, "\n", 1); close(fd); } Message Formats An Observation: In the examples above, all of the messages contain text The Rationale: The byte order doesn't matter and text is always represented using ASCII or Unicode An Alternative: Use common binary representations and network byte order A struct for a Binary Message unixexamples/udp/weather.h #ifndef WEATHER_H #define WEATHER_H #define FORECAST_PORT 22801 #define RANGE_PORT 22802 #define TEMPERATURE_PORT 22807 #define TEMPERATURE_SIZE 5 #define STATION_SIZE 3 struct range { uint16_t low; uint16_t high; }; float forecast_for(char *station); void hton_range(const struct range *h, struct range *n); void ntoh_range(const struct range *n, struct range *h); #endif A Server with a Binary Message unixexamples/udp/range_server.c #include #include #include #include #include #include #include "weather.h" int main(void) { char in[STATION_SIZE]; int fd; struct range current, out; struct sockaddr_in address, client_address; socklen_t client_length = sizeof(struct sockaddr); // Create a IP4/UDP socket fd = socket(AF_INET, SOCK_DGRAM, 0); // Initialize the address (of this host) memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_port = htons(RANGE_PORT); address.sin_addr.s_addr = htonl(INADDR_ANY); // In case the host has multiple // Bind the socket to the address bind(fd, (struct sockaddr *)&address, sizeof(struct sockaddr)); // Process requests while (1) { // Receive the request recvfrom(fd, in, STATION_SIZE, 0, (struct sockaddr *)&client_address, &client_length); // Create the response current.low = (uint16_t)forecast_for(in); current.high = (uint16_t)forecast_for(in); // Convert the respons to network byte order hton_range(¤t, &out); // Send the response sendto(fd, &out, sizeof(struct range), 0, (struct sockaddr *)&client_address, client_length); } close(fd); } A Client with a Binary Message unixexamples/udp/range_client.c #include // For byte order conversions #include #include // For memset() #include #include #include "weather.h" int main(int argc, char *argv[]) { char out[] = "JMU"; int fd; struct range current, in; struct sockaddr_in server_address; if (argc > 1) strncpy(out, argv[1], STATION_SIZE); // Create a IP4/UDP socket fd = socket(AF_INET, SOCK_DGRAM, 0); // Initialize the address of the server memset(&server_address, 0, sizeof(struct sockaddr_in)); server_address.sin_family = AF_INET; inet_pton(AF_INET, "134.126.125.234", &(server_address.sin_addr)); server_address.sin_port = htons(RANGE_PORT); // Send the request sendto(fd, out, STATION_SIZE, 0, (struct sockaddr *)&server_address, sizeof(server_address)) ; // Receive the response recvfrom(fd, &in, TEMPERATURE_SIZE, 0, NULL, NULL); // Convert from network byte order to host byte order ntoh_range(&in, ¤t); // DIsplay the converted response printf("Low: %d\n", current.low); printf("High: %d\n", current.high); close(fd); } Sequential and Concurrent Servers A Question You Should Have Asked: What happens if a server receives a request while it is processing another request? The Answer: The request is buffered Sequential and Concurrent Servers (cont.) The Implication: The server only handles one request "at a time" Using Concurrent Processing to Handle Multiple Requests: Use multiple processes Use multiple threads A Server with Multiple Processes unixexamples/udp/multiprocessed_forecast_server.c #include #include #include #include #include #include #include #include "weather.h" int main(void) { char in[STATION_SIZE], out[TEMPERATURE_SIZE]; int ifd, ofd, pid; struct sockaddr_in address, client_address; socklen_t client_length = sizeof(struct sockaddr); // Create an IP4/UDP socket ifd = socket(AF_INET, SOCK_DGRAM, 0); // Initialize the address of this host memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_port = htons(FORECAST_PORT); address.sin_addr.s_addr = htonl(INADDR_ANY); // In case the host has multiple // Bind the socket to the address bind(ifd, (struct sockaddr *)&address, sizeof(struct sockaddr)); // Handle requests (each in its own child process) while (1) { // Receive the request recvfrom(ifd, in, STATION_SIZE, 0, (struct sockaddr *)&client_address, &client_length); // Create the child process pid = fork(); if (pid == 0) { // Close the child's copy of the incoming socket close (ifd); // Send the response memset(&out, 0, TEMPERATURE_SIZE); sprintf(out, "%5.1f", forecast_for(in)); ofd = socket(AF_INET, SOCK_DGRAM, 0); sendto(ofd, out, TEMPERATURE_SIZE, 0, (struct sockaddr *)&client_address, client_length); close(ofd); exit(0); } } close(ifd); } A Server with Multiple Threads unixexamples/udp/threaded_forecast_server.c #include #include #include #include #include #include #include #include "weather.h" // The arguments needed to send a response struct thread_arguments { char station[STATION_SIZE]; struct sockaddr client_address; socklen_t client_length; }; // The entry point for the threads static void *send_response(void *arg) { char out[TEMPERATURE_SIZE]; int fd; struct thread_arguments *args; // Cast the arguments args = (struct thread_arguments *)arg; memset(&out, 0, TEMPERATURE_SIZE); sprintf(out, "%5.1f", forecast_for(args->station)); fd = socket(AF_INET, SOCK_DGRAM, 0); sendto(fd, out, TEMPERATURE_SIZE, 0, &(args->client_address), args->client_length); close(fd); // Free the memory used by the arguments // (Caller Allocates/Callee Frees) free(args); return NULL; } int main(void) { char in[STATION_SIZE]; int fd; pthread_t helper; struct sockaddr_in address, client_address; struct thread_arguments *args; socklen_t client_length = sizeof(struct sockaddr); // Create an IP4/UDP socket fd = socket(AF_INET, SOCK_DGRAM, 0); // Initialize the address of this host memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_port = htons(FORECAST_PORT); address.sin_addr.s_addr = htonl(INADDR_ANY); // In case the host has multiple // Bind the socket to the address bind(fd, (struct sockaddr *)&address, sizeof(struct sockaddr)); // Process requests while (1) { // Receive the request recvfrom(fd, in, STATION_SIZE, 0, (struct sockaddr *)&client_address, &client_length); // Make a copy of the message and the client address // for the thread that will handle the response // (Caller Allocates/Callee Frees) args = (struct thread_arguments *)malloc(sizeof(struct thread_arguments)); strncpy(args->station, in, STATION_SIZE); memcpy(&(args->client_address), &client_address, client_length); args->client_length = client_length; // Create a thread to handle the response pthread_create(&helper, NULL, send_response, (void *)args); pthread_detach(helper); } close(fd); } Improving Concurrent Servers Pre-Forking: Instead of child processes when needed, create them at start-up (and place them in a pool) Connections are placed in a queue When a child process is done with a connection it doesn't terminate; instead it retrieves the next connection in the queue Pre-Threading: The same idea, but using threads instead of processes Socket Options: setsockopt() int setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) Purpose: Set socket options Details: fd The file descriptor of the UDP socket level SOL_SOCKET, IPPROTO_IP, ... optname The option to set optval The value of the option optlen The size of the optval argument Return 0 on success; -1 on error #include Socket Options (cont.) Transaction-Related UDP Option Names: SO_SNDTIMEO and SO_RCVTIMEO allow you to set timeouts (i.e., how long a call will block before failing) SO_LINGER allows the socket to delay closing if there are data to send Setup-Related UDP Option Names: SO_REUSEADDR and SO_REUSEPORT allow you to re-use an address and/or port even if they are already bound (which can be useful when a server fails and must be restarted) SO_RCVBUF and SO_SNDBUF allow you to change buffer sizes Socket Options (cont.) A Partial Example struct timeval timeout; timeout.tv_sec = 1; timeout.tv_usec = 0; setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval));