TCP Socket Programming
An Introduction with Examples in C |
Prof. David Bernstein |
Computer Science Department |
bernstdh@jmu.edu |
int accept(int fd, struct sockaddr *addr, socklen_t *addrlen)
fd
|
The file descriptor of the passive socket |
addr
|
The address of the active socket that initiated the connection (or NULL if not needed) |
addrlen
|
The length of addr |
Return | The file descriptor for the connection on success; -1 on error |
Notes: (1) accept()
blocks (unless there are pending connections).
(2) The file descriptor that is returned has an associated active
socket. In other words, an active socket is created by the passive
socket each time accept()
returns.
#include <fcntl.h> #include <netdb.h> #include <stdio.h> // For sprintf() #include <string.h> // For memset() #include <sys/socket.h> #include <unistd.h> #include "djia_lib.h" #define PORT 22805 int main(void) { char response[6]; float djia; int connection_fd, listening_fd; struct sockaddr_in address; // Initialize the address of this host memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_port = htons(PORT); address.sin_addr.s_addr = htonl(INADDR_ANY); // In case the host has multiple // Create the socket listening_fd = socket(AF_INET, SOCK_STREAM, 0); // Bind the socket to a specific port bind(listening_fd, (struct sockaddr *)&address, sizeof(struct sockaddr)); // Mark the port as passive listen(listening_fd, 0); // No backlog // Handle requests (one at a time) while (1) { // Accept the connection connection_fd = accept(listening_fd, NULL, NULL); // Format the response djia = get_djia(); snprintf(response, 6, "%5.0f", djia); // Write the response write(connection_fd, response, 5); // Close the connection close(connection_fd); } // Should close the socket (and use a better loop) //close(listening_fd); return 0; }
int connect(int fd, const struct sockaddr *addr, socklen_t addrlen)
fd
|
The file descriptor of the active socket making the request |
addr
|
The address of the passive socket |
addrlen
|
The length of the address of the passive socket |
Return | 0 on success; -1 on error |
#include <arpa/inet.h> // For byte order conversions #include <fcntl.h> #include <netdb.h> #include <string.h> // For memset() #include <sys/socket.h> #include <unistd.h> #define PORT 22805 int main(void) { char djia[5]; int fd; struct sockaddr_in server; // Initialize the address of the server memset(&server, 0, sizeof(server)); server.sin_family = AF_INET; inet_pton(AF_INET, "134.126.125.234", &(server.sin_addr)); server.sin_port = htons(PORT); // Create a socket fd = socket(AF_INET, SOCK_STREAM, 0); // Initiate a connection with the server connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr)); // Read the response read(fd, djia, 5); // Display the response write(STDOUT_FILENO, djia, 5); write(STDOUT_FILENO, "\n", 1); // Close the connection close(fd); return 0; }
telnet
:
telnet
for Other Purposes:
telnet
uses TCP at the transport
layer and reverts to "old line-by-line mode" if the remote
party doesn't support TELNET, it can be used to communicate
with other applications that use TCP#include <fcntl.h> #include <netdb.h> #include <stdlib.h> #include <string.h> // For memset() #include <sys/socket.h> #include <unistd.h> #include "balance_lib.h" #define PORT 22803 int main(void) { char challenge_string[2], id_string[2], response_string[2]; int connection_fd, listening_fd; int challenge, id, response; struct sockaddr_in address; // Initialize the address of this host memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_port = htons(PORT); address.sin_addr.s_addr = htonl(INADDR_ANY); // In case the host has multiple // Create the socket listening_fd = socket(AF_INET, SOCK_STREAM, 0); // Bind the socket to a specific port bind(listening_fd, (struct sockaddr *)&address, sizeof(struct sockaddr)); // Mark the port as passive listen(listening_fd, 0); // No backlog // Handle requests (one at a time) while (1) { // Accept the connection connection_fd = accept(listening_fd, NULL, NULL); // Read the user ID read(connection_fd, id_string, 1); id_string[1] = '\0'; id = atoi(id_string); // Send the challenge challenge_string[0] = get_challenge(id); challenge_string[1] = '\0'; challenge = atoi(challenge_string); write(connection_fd, challenge_string, 1); // Read the response read(connection_fd, response_string, 1); response_string[1] = '\0'; response = atoi(response_string); // Verify and send the appropriate response if (check_response(id, challenge, response)) { write(connection_fd, get_balance(id), 5); } else { write(connection_fd, "XXXXX", 5); } // Close the connection close(connection_fd); } // Should close the socket (and use a better loop) //close(listening_fd); return 0; }
#include <arpa/inet.h> // For byte order conversions #include <fcntl.h> #include <netdb.h> #include <string.h> // For memset() #include <sys/socket.h> #include <unistd.h> #define PORT 22803 int main(void) { char challenge_string[2], id_string[2], response_string[2]; char balance_string[5]; int fd; struct sockaddr_in server; // Initialize the address of the server memset(&server, 0, sizeof(server)); server.sin_family = AF_INET; inet_pton(AF_INET, "134.126.125.234", &(server.sin_addr)); server.sin_port = htons(PORT); // Create a socket fd = socket(AF_INET, SOCK_STREAM, 0); // Initiate a connection with the server connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr)); // Prompt the user for her/his ID write(STDOUT_FILENO, "ID: ", 4); read(STDIN_FILENO, id_string, 2); // Send the ID write(fd, id_string, 1); // Receive the challenge read(fd, challenge_string, 1); // Display the challenge string write(STDOUT_FILENO, "Challenge: ", 11); write(STDOUT_FILENO, challenge_string, 1); write(STDOUT_FILENO, "\n: ", 1); // Prompt the user for her/his response write(STDOUT_FILENO, "Response: ", 11); read(STDIN_FILENO, response_string, 1); // Transmit the response write(fd, response_string, 1); // Read the balance read(fd, balance_string, 5); // Display the balance write(STDOUT_FILENO, "Balance: ", 9); write(STDOUT_FILENO, balance_string, 5); write(STDOUT_FILENO, "\n", 1); // Close the connection close(fd); return 0; }
telnet
) sends a course code#include <fcntl.h> #include <netdb.h> #include <string.h> // For memset() #include <sys/socket.h> #include <unistd.h> #include "course_lib.h" #define PORT 22802 int main(void) { char id[4]; int connection_fd, listening_fd; int i, index, n; struct sockaddr_in address; // Initialize the address of this host memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_port = htons(PORT); address.sin_addr.s_addr = htonl(INADDR_ANY); // In case the host has multiple // Create the socket listening_fd = socket(AF_INET, SOCK_STREAM, 0); // Bind the socket to a specific port bind(listening_fd, (struct sockaddr *)&address, sizeof(struct sockaddr)); // Mark the port as passive listen(listening_fd, 0); // No backlog // Handle requests (one at a time) while (1) { // Accept the connection connection_fd = accept(listening_fd, NULL, NULL); // Read the course ID read(connection_fd, id, 3); id[3] = '\0'; // Write the response index = get_index(id); if (index < 0) { write(connection_fd, "No Such Course", 15); } else { n = lines[index]; for (i=0; i<n; i++) { write(connection_fd, description[index][i], 70); write(connection_fd, "\n", 1); } } // Close the connection close(connection_fd); } // Should close the socket (and use a better loop) //close(listening_fd); return 0; }
#include <fcntl.h> #include <pthread.h> #include <netdb.h> #include <string.h> // For memset() #include <sys/socket.h> #include <unistd.h> #include "sync_lib.h" #define PORT 22806 // The function to be executed in the thread handling outbound traffic static void *outbound(void *arg) { int fd, i; fd = (int)arg; for (i=0; i<FILE_LENGTH; i++) { write(fd, read_measurement(i), MESSAGE_LENGTH); } return NULL; } // The function to be executed in the thread handling inbound traffic static void *inbound(void *arg) { char message[MESSAGE_LENGTH]; int fd, i; fd = (int)arg; for (i=0; i<FILE_LENGTH; i++) { read(fd, message, MESSAGE_LENGTH); // Echo the inbound message write(STDOUT_FILENO, "From client: ", 13); write(STDOUT_FILENO, message, MESSAGE_LENGTH); write(STDOUT_FILENO, "\n", 1); } return NULL; } int main(void) { int connection_fd, listening_fd; pthread_t sending_thread, receiving_thread; socklen_t client_length; struct sockaddr_in address; struct sockaddr_in client; // Initialize the address of this host memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_port = htons(PORT); address.sin_addr.s_addr = htonl(INADDR_ANY); // In case the host has multiple // Create a socket listening_fd = socket(AF_INET, SOCK_STREAM, 0); // Bind the socket to a port bind(listening_fd, (struct sockaddr *)&address, sizeof(struct sockaddr)); // Mark the socket as passive listen(listening_fd, 0); // No backlog // Accept a (single) connection connection_fd = accept(listening_fd, (struct sockaddr *)&client, &client_length); // Start the thread that handles outbound traffic pthread_create(&sending_thread, NULL, outbound, (void *)connection_fd); // Start the thread that handles inbound traffic pthread_create(&receiving_thread, NULL, inbound, (void *)connection_fd); // Wait for both helper threads to finish pthread_join(sending_thread, NULL); pthread_join(receiving_thread, NULL); // Close the connection close(connection_fd); // Close the passive socket close(listening_fd); return 0; }
#include <arpa/inet.h> // For byte order conversions #include <fcntl.h> #include <pthread.h> #include <netdb.h> #include <string.h> // For memset() #include <sys/socket.h> #include <unistd.h> #include "sync_lib.h" #define PORT 22806 // The function to be executed in the thread handling outbound traffic static void *outbound(void *arg) { int fd, i; fd = (int)arg; for (i=0; i<FILE_LENGTH; i++) { write(fd, read_measurement(i), MESSAGE_LENGTH); } return NULL; } // The function to be executed in the thread handling inbound traffic static void *inbound(void *arg) { char message[MESSAGE_LENGTH]; int fd, i; fd = (int)arg; for (i=0; i<FILE_LENGTH; i++) { read(fd, message, MESSAGE_LENGTH); // Echo the inbound message write(STDOUT_FILENO, "From server: ", 13); write(STDOUT_FILENO, message, MESSAGE_LENGTH); write(STDOUT_FILENO, "\n", 1); } return NULL; } int main(void) { int fd; pthread_t sending_thread, receiving_thread; struct sockaddr_in server; // Initialize the address of the server memset(&server, 0, sizeof(server)); server.sin_family = AF_INET; inet_pton(AF_INET, "134.126.125.234", &(server.sin_addr)); server.sin_port = htons(PORT); // Create a socket fd = socket(AF_INET, SOCK_STREAM, 0); // Establish a connection with the server connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr)); // No backlog // Create a thread for the outbound traffic pthread_create(&sending_thread, NULL, outbound, (void *)fd); // Create a thread for the inbound traffic pthread_create(&receiving_thread, NULL, inbound, (void *)fd); // Wait for both helper threads to finish pthread_join(sending_thread, NULL); pthread_join(receiving_thread, NULL); // Close the connection close(fd); return 0; }
#include <fcntl.h> #include <netdb.h> #include <pthread.h> #include <stdlib.h> // For exit() #include <string.h> // For memset() #include <sys/socket.h> #include <unistd.h> #include "course_lib.h" #define PORT 22802 static void handle_connection(int connection_fd) { char id[4]; int i, index, n; // Read the course ID read(connection_fd, id, 3); id[3] = '\0'; // Write the response index = get_index(id); if (index < 0) { write(connection_fd, "No Such Course", 15); } else { n = lines[index]; for (i=0; i<n; i++) { write(connection_fd, description[index][i], 70); write(connection_fd, "\n", 1); } } // Close the connection close(connection_fd); } int main(void) { int connection_fd, listening_fd; int pid; struct sockaddr_in address; // Initialize the address of this host memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_port = htons(PORT); address.sin_addr.s_addr = htonl(INADDR_ANY); // In case the host has multiple // Create the socket listening_fd = socket(AF_INET, SOCK_STREAM, 0); // Bind the socket to a specific port bind(listening_fd, (struct sockaddr *)&address, sizeof(struct sockaddr)); // Mark the port as passive listen(listening_fd, 0); // No backlog // Handle requests (concurrently, in different processes) while (1) { // Accept the connection connection_fd = accept(listening_fd, NULL, NULL); // Create a process to handle the connection // (Remember: The file descriptors are copied/inherited) pid = fork(); switch(pid) { case -1: close(connection_fd); break; case 0: // Child close(listening_fd); // Close the child's copy handle_connection(connection_fd); // Handle the connection exit(0); // Terminate the child default: // Parent close(connection_fd); // Close the parent's copy break; } } // Should close the socket (and use a better loop) //close(listening_fd); return 0; }
#include <fcntl.h> #include <netdb.h> #include <pthread.h> #include <string.h> // For memset() #include <sys/socket.h> #include <unistd.h> #include "course_lib.h" #define PORT 22802 static void *handle_connection(void *args) { char id[4]; int i, index, n; int connection_fd; connection_fd = (int)args; // Read the course ID read(connection_fd, id, 3); id[3] = '\0'; // Write the response index = get_index(id); if (index < 0) { write(connection_fd, "No Such Course", 15); } else { n = lines[index]; for (i=0; i<n; i++) { write(connection_fd, description[index][i], 70); write(connection_fd, "\n", 1); } } // Close the connection close(connection_fd); } int main(void) { int connection_fd, listening_fd; pthread_t connection_thread; struct sockaddr_in address; // Initialize the address of this host memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_port = htons(PORT); address.sin_addr.s_addr = htonl(INADDR_ANY); // In case the host has multiple // Create the socket listening_fd = socket(AF_INET, SOCK_STREAM, 0); // Bind the socket to a specific port bind(listening_fd, (struct sockaddr *)&address, sizeof(struct sockaddr)); // Mark the port as passive listen(listening_fd, 0); // No backlog // Handle requests (concurrently, in different threads) while (1) { // Accept the connection connection_fd = accept(listening_fd, NULL, NULL); // Create a thread to handle the response pthread_create(&connection_thread, NULL, handle_connection, (void *)connection_fd); // Let the thread execute and terminate independently pthread_detach(connection_thread); } // Should close the socket (and use a better loop) //close(listening_fd); return 0; }
read()
and write()
may read/write
fewer characters than were requested (and return the number
actually read/written)#include <errno.h> #include <unistd.h> #include "tcpio.h" ssize_t readn(int fd, char *buffer, size_t n) { char *position; size_t received; ssize_t remaining; position = buffer; remaining = n; while (remaining > 0) { received = read(fd, position, remaining); if (received < 0) { if (errno == EINTR) received = 0; // Interrupted by a signal else return -1; } else if (received == 0) return n-remaining; remaining -= received; position += received; } return n-remaining; } ssize_t writen(int fd, const char *buffer, size_t n) { const char *position; size_t sent; ssize_t remaining; position = buffer; remaining = n; while (remaining > 0) { sent = write(fd, position, remaining); if (sent < 0) { if (errno == EINTR) sent = 0; // Interrupted by a signal else return -1; } else if (sent == 0) return -1; remaining -= sent; position += sent; } return n; }