Communication between different hosts: ❤️
-
The concept of process communication originated from single machine system. Since each process runs within its own address range, the operating system provides corresponding facilities for process communication to ensure that two processes communicating with each other do not interfere with each other and work in coordination:
- UNIX BSD includes: pipe, named pipe and soft interrupt signal
- UNIX system V includes: message, shared memory, semaphore, etc
-
The above methods of interprocess communication rely on the Linux kernel, so they can only be used for communication between native processes. Inter network process communication solves the problem of mutual communication between different host processes
-
IP address: the unique 32-bit address specified for each computer on the Internet is called "IP address", also known as "Internet structure". IP address has a fixed and standardized format. It is composed of 32-bit binary numbers, divided into 4 segments, of which every 8 bits form a segment. In this way, the maximum range of binary numbers represented by each segment does not exceed 255, and "is used between segments" "Separated. In order to facilitate identification and expression, the IP address is expressed in decimal form, with one decimal number for every 8-bit binary number.
#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int inet_aton(const char* straddr,struct in_addr *addrp);//The first parameter is decimal IP, and the second parameter points to the storage of binary char* inet_ntoa(struct in_ addr inaddr);//Binary to fractional decimal
-
TCP/IP (Transmission Control Protocol/Internet Protocol), namely transmission control protocol / inter network protocol, is an industrial standard protocol set, which is designed for wide area networks (WANs).
-
TCP/IP protocol exists in the OS. Network services are provided through the OS. Berkeley sockets, such as Socket, Connect, Send, Recv and so on, are added to the OS to support TCP/IP system calls
-
UDP (User Data Protocol) is a protocol corresponding to TCP. It belongs to the TCP/IP protocol family:
- TCP/IP protocol family includes transport layer, network layer and link layer. The location of socket is shown in the figure. Socket is the intermediate software abstraction layer for the communication between application layer and TCP/IP protocol family.
socket: ❤️
- socket is a special file (S), which can be operated in the "open – > read / write/read – > close" mode
- Socket is an intermediate software abstraction layer between application layer and TCP/IP protocol family. It is a group of interfaces. In the design mode, socket is actually a facade mode. It hides the complex TCP/IP protocol family behind the socket interface. For users, a group of simple interfaces is all, allowing the socket to organize data to comply with the specified protocol.
- In fact, socket does not have the concept of layer. It is just an application of facade design pattern, which makes programming easier. Is a software abstraction layer. In network programming, we use a lot of sockets.
Network byte order and host byte order: ❤️
-
Byte order, as the name suggests, is the storage order of data greater than one byte type in memory
-
Host byte order is what we usually call large end and small end modes: different CPU s have different byte order types. These byte orders refer to the order in which integers are saved in memory. This is called host order. The definitions of big endian and little endian referring to the standard are as follows:
- Little endian means that the low order bytes are placed at the low address end of the memory and the high order bytes are placed at the high address end of the memory.
- Big endian means that the high-order bytes are arranged at the low address end of the memory, and the low-order bytes are arranged at the high address end of the memory.
The above figure is from the network
-
Network byte order: 32bit values of 4 bytes are transmitted in the following order: first 0 ~ 7bit, then 8 ~ 15bit, then 16 ~ 23bit, and finally 24~31bit. This transmission order is called big endian byte order. Because all binary integers in TCP/IP header are required to be transmitted in this order in the network, it is also called network byte order.
-
Byte order conversion function
#include <arpa/inet.h> uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort); //h represents host, n represents network, l represents 32-bit long integer, and s represents 16 bit short integer.
Socket programming: ❤️
General steps of Socket programming
Server:
-
To create a Socket, use the Socket() function
-
Set Socket properties
-
To add information (IP address and port number) to the socket, use the bind() function
-
Enable listening and use the listen() function
-
Listen for client access, accept a connection, and use the accept() function
-
To exchange data, use the functions send() and recv(), or read(), write()
-
Close the socket and disconnect
client:
- Create a Socket and use the Socket function
- Set Socket properties
- To connect to the server, use the connect() function
- To exchange data, use the functions send() and recv(), or read(), write()
- Close network connection
socket interface function
Header file
#include <sys/types.h>
#include <sys/socket.h>
Socket function
-
Function prototype
int socket(int domain, int type, int protocol);
-
Function: a function used to allocate the description word of a socket interface and its resources according to the specified address family, data type and protocol
-
Parameters:
- Protocol family: protocol family. Commonly used protocol families include AF_INET(IPV4) and AF_INET6(IPV6),AF_LOCAL,AF_ROUTE, wait. The protocol family determines the address type of socket, and the corresponding address must be used in communication, such as AF_ INET decides to use the combination of ipv4 address (32-bit) and port number (16 bit), AF_UNIX decides to use an absolute pathname as the address.
- Type: Specifies the socket type. The commonly used socket types are SOCK_STREAM,SOCK_DGRAM,SOCK_RAW,SOCK_PACKET,SOCK_SEQPACKET, etc.
- Protocol: Specifies the protocol. Commonly used protocols are IPPROTO_TCP,IPPTOTO_UDP,IPPROTO_SCTP,IPPROTO_TIPC, etc., which correspond to TCP transmission protocol, UDP transmission protocol, STCP transmission protocol and TIPC transmission protocol respectively.
-
Return value: non negative integer (socket descriptor) is returned on success, and - 1 is returned on failure.
-
The socket function corresponds to the opening operation of ordinary files. The opening operation of ordinary files returns a file descriptor, and socket() is used to create a socket descriptor, which uniquely identifies a socket. This socket descriptor is the same as the file descriptor. It is used in subsequent operations. Take it as a parameter to carry out some read-write operations.
bind function
-
Function prototype
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
-
Function: bind IP address and port number to Sockfd
-
sockfd: a socket descriptor returned by the socket function call
-
addr: a pointer to the sockaddr type containing the local IP address, port number and other information. It points to the protocol address structure to be bound to sockfd. This address structure varies according to the address protocol family when creating the socket.
- Structure for ipv4:
struct sockaddr_in { sa_family_t sin_family; /* address family: AF_INET */ in_port_t sin_port; /* port in network byte order */ struct in_addr sin_addr; /* internet address */ }; /* Internet address. */ struct in_addr { uint32_t s_addr; /* address in network byte order */ };
-
addrlen: the size of the structure in the second parameter
-
Return value: 0 for success and - 1 for error
listen and connect functions
-
Function prototype
int listen(int sockfd, int backlog);//Turn the process into a server and specify the corresponding socket to become a passive connection. Specifies the maximum number of connections queued by the kernel for the corresponding socket int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);//After binding, the client side (client side) establishes connection parameters with the server
-
If a server calls socket() and bind(), it will call listen() to listen to the socket. If the client calls connect() to make a connection request, the server will receive the request.
-
The first parameter of the listen function is the socket description word to listen, and the second parameter is the maximum number of connections that the corresponding socket can queue. The socket created by the socket() function is an active type by default. The listen function changes the socket to a passive type and waits for the connection request of the customer.
-
The first parameter of the connect function is the socket description word of the client, the second parameter is the socket address of the server, and the third parameter is the length of the socket address. The client establishes a connection with the TCP server by calling the connect function.
-
Return value: 0 for success and - 1 for error
accept function
-
Function prototype
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); //Return to connectconnect_ fd
-
After calling socket(), bind(), listen() in turn, the TCP server will listen to the specified socket address. After calling socket() and connect() in turn, the TCP client sends a connection request to the TCP server. After listening to the request, the TCP server will call the accept() function to receive the request, so that the connection is established. After that, you can start the network I/O operation, that is, the read-write I/O operation similar to ordinary files.
-
Parameters:
-
sockfd: listening socket. This socket is used to listen to a port. When a client is connected to the server, it uses this port number, and this port number is associated with this socket.
-
addr: This is a result parameter. It is used to accept a return value. The return value specifies the address of the client. Of course, this address is described by an address structure. The user should know what kind of address structure it is. If you are not interested in the customer's address, you can set this value to NULL.
-
len: the size of the addr structure, which indicates the number of bytes occupied by the addr structure. Can be set to NULL.
-
-
Return value: accept blocks the process by default until a client connection is established. It returns a newly available socket, which is a connection socket. Failure returns - 1.
-
If accept returns successfully, the server and the client have correctly established a connection. At this time, the server completes the communication with the client through the socket returned by accept.
Code example: ❤️
-
Client c:
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <arpa/inet.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/wait.h> int main(int argc,char**argv) { int n_read; char readBuf[128] = {0}; char data[64]={0}; int c_fd = socket(AF_INET,SOCK_STREAM,0); if(c_fd == -1){ perror("socket error"); exit(-1); } struct sockaddr_in c_addr; c_addr.sin_family = AF_INET; c_addr.sin_port = htons(atoi(argv[2])); inet_aton(argv[1],&c_addr.sin_addr); if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(c_addr)) == -1){ perror("connect error"); exit(-1); } if(fork() == 0){ while(1){ printf("put:"); memset(data, 0, strlen(data)); gets(data); write(c_fd,data,strlen(data)); n_read = read(c_fd,readBuf,128); if(n_read == -1){ perror("read error"); exit(-1); }else{ printf("get server data %dbyte:%s\n",n_read,readBuf); } } } wait(NULL); return 0; }
-
Server c:
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <arpa/inet.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/wait.h> int main(int argc,char**argv) { int n_read; char readBuf[128] = {0}; int c_fd; int s_fd = socket(AF_INET,SOCK_STREAM,0); if(s_fd == -1){ perror("socket error"); exit(-1); } struct sockaddr_in s_addr; s_addr.sin_family = AF_INET; s_addr.sin_port = htons(atoi(argv[2])); inet_aton("argv[1]",&s_addr.sin_addr); bind(s_fd,(struct sockaddr *)&s_addr,sizeof(s_addr)); listen(s_fd,10); struct sockaddr_in c_addr; int c_size = sizeof(c_addr); while(1){ c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&c_size); if(c_fd == -1){ perror("accept error"); exit(-1); } printf("get connect:%s\n",inet_ntoa(c_addr.sin_addr)); if(fork() == 0){ while(1){ memset(readBuf, 0, strlen(readBuf)); n_read = read(c_fd,readBuf,128); if(n_read == -1){ perror("read error"); exit(-1); }else{ printf("get data %dbyte:%s\n",n_read,readBuf); write(c_fd,"I get it!",strlen("I get it!")); } } } } wait(NULL); return 0; }
-
Terminal input (the second parameter is IP address, 127.0.0.1 is local loopback; the third parameter is port number, and the unoccupied port can be written freely):
./client.out 127.0.0.1 6666 ./server.out 127.0.0.1 6666
-
client
-
Server: