/* This is derived from better_server.c * Look for comments in better_server_commented.c or simple_server_commented.c if * something isn't explained very well here. */ #include #include #include #include #include #include #include #include #include int skt; void shut_down_server(int signal){ printf("\nDoing everything we need to do to shut down the server\n"); close(skt); exit(0); } /* Protocol: * The server will send out: * (2 bytes, unsigned integer in little-endian order) message length * (variable, message length bytes) ASCII string, not null terminated * (4 bytes, signed integer in little-endian order) moosenum * (8 bytes, 64-bit float point, C double) mooseweight */ /* This function sends out a complete protocol message to the client. The client will have * to read things exactly as we just wrote them. No more bytes, no fewer bytes. */ void send_data_to_client(int client_fd){ char* message = "There are moose swimming in the hot tub"; size_t total_written = 0; /* write expects an address for the second parameter, not a number to send. So we * have to put messagelen into a variable and use that variable's address */ uint16_t messagelen = strlen(message); // uint16_t limits length to 65,535 characters write(client_fd, &messagelen, 2); // this'll be sent in little endian /* Once strlen has been called, we shouldn't call it again, because that * would be a waste of time. It has to loop down the whole string until it * finds a null terminator, so it's not super fast. */ ssize_t writelen = write(client_fd, message, messagelen); total_written += writelen; printf("writelen = %ld\n", writelen); /* usleep(10000) will sleep for 10 milliseconds * This isn't very long, but it's long enough that TCP will decide to send out everything * we've got ready so far (the message length and message), and will stop waiting for * anything more. The next part will be in a new packet. Don't use usleep to do * this kind of thing in a real server. It's only here to make things harder for the client! */ usleep(10000); if(writelen != strlen(message)){ return; } int32_t moosenum = 35; writelen = write(client_fd, &moosenum, 4); // also little endian total_written += writelen; // we could, and probably should, check to see if writelen == sizeof(moosenum) double mooseweight = 1408.32; writelen = write(client_fd, &mooseweight, sizeof(mooseweight)); total_written += writelen; // again, should check writelen == sizeof(mooseweight) printf("In total, we wrote %lu bytes\n", total_written); } int main(int argc, char ** argv){ uint16_t listen_port = 5141; // 5141 is the default if(argc > 1){ listen_port = atoi(argv[1]); if(listen_port < 1){ printf("Invalid port: %s\n", argv[1]); exit(1); } printf("Will listen on port %d\n", listen_port); } else { printf("No port specified, defaulting to %d\n", listen_port); } struct sigaction sa; sa.sa_handler = shut_down_server; sigaction(SIGINT, &sa, 0); struct sockaddr_in sad; sad.sin_port = htons(listen_port); sad.sin_addr.s_addr = INADDR_ANY; sad.sin_family = AF_INET; skt = socket(AF_INET, SOCK_STREAM, 0); // Step 1 if(skt == -1){ perror("socket"); return 1; } if( bind(skt, (struct sockaddr *)(&sad), sizeof(struct sockaddr_in)) ){ // step 2 perror("bind"); return 1; } if( listen(skt, 5) ){ // step 3 perror("listen"); return 1; } int client_fd; struct sockaddr_in client_address; socklen_t address_size = sizeof(struct sockaddr_in); while(1){ client_fd = accept(skt, (struct sockaddr *)(&client_address), &address_size); // step 4 printf("Connection made from address %s\n", inet_ntoa(client_address.sin_addr)); send_data_to_client(client_fd); close(client_fd); } return 0; }