Overview socket() – get file descriptors! Bind () — Which port are we on? The connect (), Hello! Listen () — Has anyone called me? Accept () –“Thank you for calling port 3490.” Send () and recv() –Talk to me, baby! Sendto () and recvfrom() –Talk to me, dgram-style close() and shutdown() — get lost! Getpeername () — Who are you? Gethostname () — Who am I? DNS – You say “White House”, I say “198.137.240.100”
C/C++, Linux, Golang technology, Nginx, ZeroMQ, MySQL, Redis, Fastdfs, MongoDB, ZK, Streaming media, CDN, P2P, K8S, Docker, TCP/IP, coroutine, DPDK, FFMPEG, etc.)
#include <sys/types.h> #include <sys/socket.h> int socket(int family, int type, int protocol); The sockFD socket function specifies the protocol family (IPv4, IPv6, or Unix) and socket type (byte stream, datagram, or primitive socket). No local or remote protocol address is specified. Understand socket How to communicate with other programs using Unix file descriptors (FILE descriptors). When a Unix program performs any form of I/O, the program reads or writes a file descriptor. A file descriptor is just an integer associated with an open file. This file could be a network connection, FIFO, pipe, terminal, file on disk, or something else. Everything in Unix is a file! Therefore, when communicating with other programs on the Internet, use file descriptors. The system call socket() is used to get the file descriptor for network traffic. It returns the socket descriptor, and then calls send() and recv() through it. So why not use generic calls to read() and write() to communicate through the socket? The simple answer is: you can use normal functions! The answer is: Use send() and recv() to give you more control over the data transfer.
Establish a connection with the TCP server. #include <sys/types.h> #include <sys/socket.h> int connect(int sockfd, struct sockaddr *serv_addr, int addrlen); //sockfd is the socket file descriptor returned by the system call socket(). Serv_addr is the data structure holding the destination port and IP address The server must be prepared to accept external connections. This is done by calling the socket,bind, and 1isten functions, called Passive open. The client calls connect to initiate active OPN. This causes the client TCP to send a SYN section (for synchronization), which tells the server the initial sequence number of the data the client will send in the connection. The server must acknowledge the client’s SYN and also send a SYN section of its own that contains the initial sequence number of the data that the server will send on the same connection. The server sends a SYN and ACK for the client’s SYN in a single section. The client must confirm the server’s SYN. Error cause: No SYN response is received (server timed out,75 seconds) Returned value :ETIMEDOUT Client output :Connection time out.
Return value :ECONNREFUSE Client output :Connection refused Cause :ICMP Error: Unroutable soft Error (destination unreachable) Returned value :EHOSTUNREACH Client output :ENETUNREACH No route to host
Bind assigns a local protocol address to a socket: #include
#include
int bind(int sockfd, const struct sockaddr my_addr, int addrlen); Sockfd is the file descriptor returned by calling the socket. My_addr is a pointer to a data structure struct sockaddr that holds address (that is, port and IP address) information. Addrlen set to sizeof(struct sockaddr). Port my_addr.sin_port = 0; port my_addr.sin_port = 0; / choose an unused port at random / my_addr.sin_addr.s_addr = INADDR_ANY; / use my IP address */ bind() to select the appropriate port: assign 0 to my_addr.sin_por. Automatically fill in the IP address of the machine he is running on: my_addr.sin_addr.s_addr set to INADDR_ANY.
Listen converts an unconnected active socket to a passive socket, instructing the kernel to accept the connection request for this socket. CLOSED –? #include <sys/socket.h> int backlog (int sockfd, int backlog); Sockfd is the socket file descriptor returned by calling socket(). Backlog is the number of connections allowed in the incoming queue. Incompleted connection queue: SYN_RECV completed connection queue: SYN_RECV completed connection queue ESTABLISHED When a SYN from a client arrives, for example, when both queues are full, TCP ignores this section and does not send an RST
#include
int ACCEPT (int sockfd, struct sockaddr cliaddr, int addrlen); If the call succeeds, the following returns: 1. Cliaddr: indicates the protocol address and address size of the client process. 2. New socket descriptors (connected socket descriptors) Listening socket descriptors A given server usually generates only one listening socket and persists until the server is shut down. The connected socket Descriptor kernel creates a connected socket for each accepted client connection. When the server finishes serving a customer, the connected socket is closed. Ports smaller than 1024: used by super users
#include <sys/unistd.h> pid_t fork (void); Returns 0 in the child, -1 in the case of an error in the child’s process ID in the parent, and a typical application that calls fork twice: 1. A process can create a copy of itself. While one copy handles an operation, other copies can perform other tasks. This is a very typical web server. 2. A process wants to execute another program, and since the only way to create a new process is by calling fork, the process first calls fork to generate a copy, and then one of the copies (usually child processes) calls exec to execute the new program instead of itself.
Accept returns when a connection is established, and the server invokes fork to provide services for the client (connected through the ConnFD socket). The parent waits for another connection (listening on the socket via ListenFD). After the child process starts processing the new client, the parent process closes the connected socket. Each file or socket has an access count, maintained in a file table entry, that represents the number of descriptors that are currently open to that file or socket. After being returned from SOCK, the file entry access count associated with ListenFD is 1, and after being returned from ACCEPT, the file entry access count associated with ConnFD is also 1. When fork returns, the two description words are shared between the parent and child process. The access count of the file entry associated with the two nesting gates is both 2. When the parent closes Connfd, it simply decreases the access count from 2 to 1. The descriptor is only really closed when the access-count value reaches 0, which will happen later when the child process closes Connfd.
The close function marks the socket as “closed” and returns to the process immediately. Decrement the access counter for the socket descriptor by 1. When the access counter value is 0, the four packet connection termination sequences of TCP are raised, closing the socket. #include <sys/unistd.h> int close(int sockfd);
Getsockname and getPeerName Functions GetsockName: Getpeername: Returns the local protocol address. #include <sys/unistd.h> int getsockname (int sockfd, struct sockaddr *localaddr, int *addrlen); int getpeername(int sockfd, struct sockaddr *peeraddr, int *addrlen);
An example program: #include
#include
#include
#define MYPORT 3490 /* the port users will be connecting to / #define BACKLOG 10 / how many pending connections queue will hold / main() { int sockfd, new_fd; / listen on sock_fd, new connection on new_fd / struct sockaddr_in my_addr; / my address information / struct sockaddr_in their_addr; / connector’s address information / int sin_size; sockfd = socket(AF_INET, SOCK_STREAM, 0); / do some error checking! / my_addr.sin_family = AF_INET; / host byte order / my_addr.sin_port = htons(MYPORT); / short, network byte order / my_addr.sin_addr.s_addr = INADDR_ANY; / auto-fill with my IP / bzero(&(my_addr.sin_zero), 8); / zero the rest of the struct / / don’t forget your error checking for these calls: */ bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)); listen(sockfd, BACKLOG); sin_size = sizeof(struct sockaddr_in); new_fd = accept(sockfd, &their_addr, &sin_size); .