Socket programming 🐣
Because socket programming is very huge, this paper, as a learning note, only realizes the relatively simple and basic part, but I hope it will be helpful to you
Links to all computer network learning notes
Sockets are different when identifying communication endpoints
- External: use IP address + port number
- Internal: use socket descriptor for identification
Socket address structure:
//IP socket address structure //sockaddr_in: Internet socket address struct sockaddr_in { uint_16_t sin_family; //protocol family uint_16_t sin_port; //port struct in_addr sin_addr; //32-bit IP address unsigned char sin_zero[8]; //sizeof (struct sockaddr) } //Used for: connect, bind, accept struct sockaddr { uint16_t safamily; char sa_data[14]; }
In the connect, bind and accept functions, a pointer to the socket address structure related to the protocol is required. We set a general sockaddr data structure pointer, and then forcibly convert it into this general pointer when indicating the socket address (so that it can accept various types of socket address structures)
Explanation of socke function
cocket
Create a socket with the following functions
AF_INET indicates that we are using a 32-bit IP address
#include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol) #The non negative descriptor is returned successfully, and - 1 is returned in case of error #example clientfd = socket(SF_INET, SOCK_STREAM, 0); //default : 0
bind
The following bind, listen, accept: the server uses these functions to establish a connection with the client
The bind function tells the kernel to associate the server socket address in addr with the socket descriptor sockfd
#include <sys/socket.h> int bind(int sockfd, const struct sockaddr * addr, socklen_t addrlen); #0 returned successfully and - 1 returned in error
listen
The listen function is used to tell the kernel that the socket descriptor is used by the server rather than the client
The listen function converts sockfd from an active socket to a listening socket, which receives requests from clients.
The backlog indicates the number of queued connections
#include <sys/socket.h> int listen(int sockfd, int backlog); #0 if successful, or - 1 if not
accept
The server waits for the connection request from the client by calling the accept function
The non negative connection descriptor (connected descriptor) is returned, that is, a new socket is created to communicate with the client socket separately. The original listening descriptor continues to wait for applications from new clients, so that many client applications can be processed at the same time
#include <sys/socket.h> int accept(int listenfd, struct sockaddr * addr, int * addrlen); #The non negative connection descriptor is returned on success, and - 1 is returned on error
The read & write function is called differently, which is to interact with each other
#Read is used to read data ssize_t read (int fd, void * buf, size_t count); #Write is used to write data, which is also blocking ssize_t write(int fd, const void * buf, size_t count);
The client establishes a connection with the server whose socket address is addr by calling the connect function
The connect function will block until the connection succeeds or an error occurs
int connect (int clientfd, const struct sockaddr * addr, socklen_t addrlen);
Host byte order and network byte order are converted to each other
In order to get the correct explanation when the program is transmitted between different hosts 🦁 In addition, byte order conversion is required
uint32_t htonl(uint32_t hostlong); //32-bit host to network uint16_t htons(uint16_t hostshort); //16 bit host to network uint32_t ntohl(uint32_t netlong); //32-bit network to host uint16_t ntohs(uint16_t netshort); //16 bit network to host
Socket case
A scenario in which a peer-to-peer client sends information to the server, and then the server copies and resends the content
s e r v e r . c server.c server.c
#include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <fcntl.h> #include <sys/shm.h> const int MYPORT = 8887; const int QUEUE = 20; const int BUFFER_SIZE = 20; /* (2) struct sockaddr_in(IP Dedicated address structure) structsockaddr_in { u_char sin_len;//length u_short sin_family;//agreement u_short sin_port;//port structin_addr sin_addr;//ip address char sin_zero[8];//data }; (3) struct in_addr structin_addr {undefined u_longs_addr; }; */ //Server_addr: indicates the remote IP address and port number int main() { //Created socket int server_sockfd = socket(AF_INET, SOCK_STREAM, 0); //Define sockaddr_in struct sockaddr_in server_sockaddr; server_sockaddr.sin_family = AF_INET; server_sockaddr.sin_port = htons(MYPORT); //Conversion function of port server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); //IP address //bind returns 0 successfully and - 1 in case of error if (bind(server_sockfd, (struct sockaddr *) & server_sockaddr, sizeof(server_sockaddr)) == -1) { perror("bind"); exit(1); } printf ("monitor:%d port\n", MYPORT); //listen returns 0 if it succeeds and - 1 if it fails if (listen(server_sockfd, QUEUE) == -1) { perror("listen"); exit(1); } //Client socket char buffer[BUFFER_SIZE]; struct sockaddr_in client_addr; //The structure used to identify the client socklen_t length = sizeof (client_addr); printf("Waiting for client connection\n"); //Success - > non negative return //Failed - > Return - 1 int conn = accept(server_sockfd, (struct sockaddr*) & client_addr, & length); if (conn < 0) { perror("connect"); exit(1); } printf("Client successfully connected\n"); while (1) { memset(buffer, 0, sizeof (buffer)); int len = recv(conn, buffer, sizeof (buffer), 0); //The client terminates and exits when sending exit if (strcmp (buffer, "exit\n") == 0 || len <= 0) { break; } printf("Data from client:%s\n", buffer); send(conn, buffer, len, 0); printf("Data sent to client:%s\n", buffer); } close(conn); close(server_sockfd); return 0; }
c l i e n t . c client.c client.c
#include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <fcntl.h> #include <sys/shm.h> #define MYPORT 8887 #define BUFFER_SIZE 1024 char * SERVER_IP = "127.0.0.1"; int main() { //Define sockfd int sock_cli = socket(AF_INET, SOCK_STREAM, 0); //Define sockaddr_in struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof (servaddr)); servaddr.sin_family = AF_INET; //Define protocol family servaddr.sin_port = htons(MYPORT); servaddr.sin_addr.s_addr = inet_addr(SERVER_IP); //Server IP printf("connect%s: %d\n", SERVER_IP, MYPORT); //Connect to the server. 0 is returned successfully and - 1 is returned in error if (connect(sock_cli, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) { perror("connect\n"); exit(1); } printf("Server connection succeeded!\n"); //The connection with the newly created socket on the server side is established char sendbuf[BUFFER_SIZE]; char recvbuf[BUFFER_SIZE]; while (fgets(sendbuf, sizeof (sendbuf), stdin) != NULL ) { printf("Send data to server: %s\n", sendbuf); send(sock_cli, sendbuf, strlen(sendbuf), 0); if (strcmp(sendbuf,"exit\n") == 0) { break; //Enter exit to exit } recv(sock_cli, recvbuf, sizeof(recvbuf), 0); printf("Receive data from server:%s\n", recvbuf); memset(sendbuf, 0, sizeof (sendbuf)); memset(recvbuf, 0, sizeof (recvbuf)); } close(sock_cli); return 0; }
reference material
https://blog.csdn.net/weixin_44164489/article/details/108606391