1. The network is divided by coverage: LAN / man / WAN, Internet / Internet, Ethernet / token ring - networking mode
2. Each host must be represented by one in the network to realize point-to-point accurate communication
IP address: ipv4: uint32_t unsigned 4-byte integer} DHCP/NAT} ipv6: uint_t addr[16];
Each data in network communication must have: source IP address / destination IP address -- indicating which host the data comes from and goes to.
Destination IP address: the router in the network can select different paths for each data according to the destination address to reach the opposite host.
Source IP address: it can let the peer host know who sent the data, so as to reply to the data.
3.IP address enables the communication between hosts in the network, but there are many processes on the host: the communication must identify which process should process a piece of data
Port: uint16_t unsigned 2-byte integer 0 ~ 65535
A process can use multiple ports, but a port can only be occupied by one process.
Each data in the network must have: source port / destination port ¢ indicates which process the data comes from and goes to.
4. Why not use pid to identify the process, but use the new field port identification?
The pid of the process will change with the restart of the program, but the port will not.
5. Inter process communication (network communication) between different hosts can be realized through IP address and port
Agreement: agreement -- (agreed common rules)
Network communication protocol: agreement on data format in network communication
6. Protocol layering:
Encapsulate communication protocols in different communication environments, use different protocols at different levels and provide different services; By dividing the communication environment, the implementation of communication is simpler and easier to form specifications.
Protocol layering in network communication environment
ISO: OSI seven layer reference model: application layer / presentation layer / session layer / transport layer / network layer / link layer / physical layer
TCP/IP five layer (or four layer) model: application layer / transport layer / network layer / link layer / physical layer (less considered)
TCP/IP is a set of protocol stack / protocol cluster: it contains many protocols, and IP and TCP protocols are only two typical ones.
Application layer: responsible for data communication between applications; For example, the communication protocol between qq and qq negotiates the data format of qq; Typical protocol: HTTP/DNS/FTP
Transport layer: responsible for data transmission between processes on different hosts; Because the main information contained in the transport layer protocol is the port; Typical protocol: TCP/UDP
Network layer: responsible for address management and routing; Select an appropriate path for the data in the network; IP information; Typical protocol: IP; Typical equipment: router
Link layer: responsible for data frame identification and transmission between adjacent devices; MAC address information of network card equipment; Typical protocol: Ethernet; Typical equipment: switch
Physical layer: responsible for the transmission of physical photoelectric signals; Typical protocol: Ethernet protocol
Protocol layering: according to different services provided, different communication levels are divided, and different protocols are used at each level to realize data format conventions - simplifying and clarifying the complex network communication environment.
Data transmission process in network communication (transmission layer):
Byte order: the order in which the cpu accesses data in memory -- depending on the cpu architecture
cpu architecture: X86 architecture cpu (small end) / mips architecture cpu (large end)
0x01020304 01 is high and 04 is low
Large end byte order: low address memory high bit a[0]=01 ^ a[1]=02 ^ a[2]=03 ^ a[3]=04
Small end byte order: low address storage low bit a[0]=04 , a[1]=03 , a[2]=02 , a[3]=01
Network communication is the communication between different hosts, but the byte order on different hosts will have a great impact on the communication: Data ambiguity
Therefore, we must unify the byte order - network byte order in network communication in order to avoid this problem
No matter whether the host is a large end or a small end, the network communication is uniformly converted to the network byte order - large end byte order
If the communication host is a small end host, the data can be sent only after byte order conversion during network communication
Not all data needs to be converted: the key to the data that needs to be converted is the data with an access size of more than one byte in memory: short int long float double
But the string char buf[1024] does not need to be converted -- the string itself is stored in bytes
What needs to be converted is the small end host, but not the large end -- how to judge whether the byte order of a host is the large end or the small end?
union tmp(int a;char b(b is a[0]);) tmp. A = 1 if (TMP. B = 1) (small end)
Socket programming:
Socket is a set of network programming interface, similar to middleware; Upper layer users can simply complete network communication transmission through these interfaces; Instead of paying too much attention to the internal implementation process. Socket programming is about using socket interface to realize network communication
Quintuple: source IP address / source port / destination IP address / destination port / communication protocol -- identify a communication -- the data in each network will contain information.
socket programming: TCP/UDP (duplex communication)
The transport layer has two protocols: TCP/UDP; The two protocols are different, so the implementation process is also slightly different;
UDP: user datagram protocol; No connection, unreliable, datagram oriented;
I don't care whether the data responds or is lost.
Application scenario: a scenario where real-time data is greater than security -- video transmission
TCP: transmission control protocol: connection oriented, reliable transmission, byte stream oriented;
If a connection is established first and the server does not respond, the connection cannot be established
Application scenario: data security is greater than real-time -- file transfer
Datagram oriented: connectionless, unreliable, unnecessary, data transmission service with maximum length limit
Byte stream oriented: connection based, reliable, orderly and bidirectional byte stream transmission service} takes bytes as a unit and does not limit the size of upper layer transmission data.
Communication between two host processes in network communication: client / server
Client: the party that actively sends the request; server: the party that passively accepts the request
Always send requests from the client - > server
(this means that the client must know the address information of the server before it can package the data i layer by layer when sending data)
The data transmitted through the network should include: source IP address / destination IP address / source port / destination port / protocol
UDP network programming process:
Server side: (address permanently unchanged)
1. Create socket -- create socket structure in the kernel; Return an operation handle to the process;
Connect with the network card through the socket structure in the kernel
2. Bind address information for socket -- add various address description information (IP address and port) to the socket structure created in the kernel
The binding address is to tell the operating system which address and port I used and you received the data. If the destination address information is the same as the address information I bound, the data will be handed over to me for processing. When sending data, the source address information is the bound address information--- The server and the client bind their own address information.
When the operating system receives the data, it will judge the information of the destination address and go to the socket container in the kernel to find it one by one. If it finds it, it will put the data into the buffer received by the socket. If it is not found, it will be discarded directly.
3. Receive data -- fetch data from the receive buffer in the socket structure
Each data contains the source address and destination address, so obtaining the data will know who the opposite end is
4. Send data -- copy the data to the send buffer of the socket structure in the kernel
At this time, the operating system will take out the data from the transmission buffer at an appropriate time, and then encapsulate the data layer by layer and send it through the network card
5. If there is no communication, close the socket and release resources
client:
1. Create socket
2. Bind address information for socket
3. send data
4. receive data
5. Close socket
Introduction to socket interface:
1. Create socket
int socket(int domain, int type, int protocol);
Domain: address domain -- different network address structures_ INET - ipv4 address domain
Type: socket type -- streaming socket / datagram socket
Streaming socket: an ordered, reliable, bidirectional, connection based byte stream socket_ STREAM
Datagram socket: connectionless, unreliable, transmission socket with maximum length limit_ DGRAM
Protocol: protocol used 0 -- default protocol under different socket types; The default of streaming socket is TCP / datagram socket, and the default is UDP
IPPROTO_TCP--TCP protocol {ipproto_ UDP -- UDP protocol
Return value: returns the operation handle of the socket --- file descriptor
2. Bind the address information for the socket (convert it to a unified network byte order in order to achieve unified interface)
int bind(int sockfd, const struct sockaddr *addr, socklen_t len);
sockfd: creates the operation handle returned by the socket
addr: address information structure to bind
len: length of address information
Return value: 0 is returned successfully; Failure returned - 1
User defined SOCKADDR_ IPV4 geological structure of in is transferred into bind after strong conversion
bind(sockaddr*){
if(sockaddr->sin_family==AF_INET){
/ / this is the resolution of the ipv4 address structure
}else if(sockaddr->sin_family==AF_INT6)
}
bind((struct sockaddr*)&addr)
3. Send data
int sendto(int sockfd,char *data,int data_len,int flag,struct sockaddr *dest_addr,socklen_t len)
sockfd: socket operation handle. Sending data is to copy the data to the socket sending buffer of the kernel
Data: the first address of the data to be sent
data_len: length of data to send
flag: the option parameter , 0 by default -- indicates that the current operation is a blocking operation , MSG_ Donwait -- set to non blocking
If the socket send buffer is full when sending data, 0 will block and wait by default; MSG_ Donwait immediately returns an error
dest_addr: destination address information structure -- indicates who the data is to be sent to
Each piece of data must describe the source side information (bound address information) and the opposite side information (currently assigned information)
addr_len: address information structure length
Return value: the number of data bytes actually sent is returned successfully; failure returns - 1
4. Receive data
int recvfrom(int sockfd,char *buf ,int len, int flag, struct sockaddr *src_addr,socklen_t *addr_len);
sockfd: socket operation handle
BUF: the first address of the buffer, which is used to store the received data. Take the data from the kernel socket receiving buffer and put it into the buf user state buffer
len: the length of the data that the user wants to read, but it cannot be greater than the length of the buf buffer
flag: 0 - default blocking operation - if there is no data in the buffer, wait for MSG all the time_ Donwait - non blocking
src_addr: the address of the sender of the received data -- indicating who sent the data and where it came from -- the reply is to reply to this address
addr_len: input / output type parameter, used to specify how long address information you want to obtain; After obtaining the address, it is used to return the actual length of address information
Return value: the length of actually received data bytes is successfully returned; Failure returns - 1;
5. Close the socket
int close(int fd);
Special features of the process in the client program:
The client usually does not recommend the user to bind the address information himself, but let the operating system send the socket without binding the address when sending the data, and then automatically select an appropriate ip address and port for binding
1. If you do not actively bind, the operating system will select an appropriate address information for binding (what address is the appropriate address? -- a port that is not currently used)
A port can only be occupied by one process. If the user specifies the port and address for binding, it is possible that the port has been used, and the binding will fail. Let the operating system select the appropriate port information to avoid the probability of port conflict as much as possible.
For the client, it doesn't care what source address to use to send data, as long as it can send and receive data
2. Can the server bind the address actively or not--- may not
The address information of the server known by the client is what the server tells the client
Once the server does not actively bind the address, the operating system team doctor will choose the appropriate address for binding. The server is not sure what address information it uses and how to tell the client. Therefore, the server must usually actively bind the address and cannot change it at will
UDP server program: written in C language
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <string.h> 4 #include <netinet/in. h> / / SOCKADDR structure / IPPROTO_UDP 5 #include <arpa/inet. h> / / contains some interfaces for byte order conversion 6 #include <sys/socket. h> / / socket interface header file 7 #include <stdlib.h> 8 //Write a C language program for udp server 9 //1. Create socket 10 //2. Bind address information for socket 11 //3. Receive data 12 //4. Send data 13 //5. Close the socket 14 int main(int argc,char *argv[]){ 15 16 //argc indicates the number of parameters. Pass port parameters to the program through argv 17 if(argc!=3){ 18 printf("./udp_srv ip port em:./udp_srv 192.168.122.132 9000\n"); 19 return -1; 20 } 21 const char *ip_addr=argv[1]; 22 uint16_t port_addr=atoi(argv[2]); 23 //Socket (address domain, socket type, protocol type) 24 //1. Create socket 25 int sockfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); 26 if(sockfd<0){ 27 perror("socket error"); 28 return -1; 29 } 30 //Bind (socket descriptor, address structure, address length); 31 //struct sockaddr_in ipv4 address structure 32 struct sockaddr_in addr; 33 addr.sin_family=AF_INET; 34 //htons -- converts a 2-byte host byte order integer to a network byte order integer 35 addr.sin_port=htons(port_addr); 36 //inet_addr converts a dotted decimal string IP address to an integer IP address in network byte order 37 addr.sin_addr.s_addr=inet_addr(ip_addr); 38 socklen_t len=sizeof(struct sockaddr_in); 39 int ret=bind(sockfd,(struct sockaddr*)&addr,len); 40 if(ret<0){ 41 perror("bind error"); 42 return -1; 43 } 44 //3. Receive data 45 while(1){ 46 char buf[1024]={0}; 47 struct sockaddr_in cliaddr; 48 socklen_t len=sizeof(struct sockaddr_in); 49 //Recvfrom (descriptor, buffer, length, parameter, client address information, address information length) 50 int ret=recvfrom(sockfd,buf,1023,0,(struct sockaddr*)&cliaddr,&len); 51 if(ret<0){ 52 perror("recfrom error"); 53 return -1; 54 } 55 printf("client sya:%s\n",buf); 56 printf("server say:"); 57 fflush(stdout);//Let the user input data and send it to the client 58 memset(buf,0x00,1024);//Clear data in buf 59 scanf("%s",buf); 60 //Send the data in buf to cli addr client through sockfd 61 ret=sendto(sockfd,buf,strlen(buf),0,(struct sockaddr *)&cliaddr,len); 62 if(ret<0){ 63 perror("sendto error"); 64 return -1; 65 } 66 } 67 close(sockfd);//5. Close the socket 68 } 69
UDP client program: use C + + to encapsulate a udpsocket class, and provide a simple interface to implement a client / server
1 #include <cstdio> 2 #include <unistd.h> 3 #include <string.h> 4 #include <netinet/in. h> / / SOCKADDR structure / IPPROTO_UDP 5 #include <arpa/inet. h> / / contains some interfaces for byte order conversion 6 #include <sys/socket. h> / / socket interface header file 7 #include <iostream> 8 #include <stdlib. h> / / ATOI interface 9 //Encapsulate a UDP socket class to provide a simple interface to implement socket programming 10 class UdpSocket{ 11 12 public: 13 UdpSocket():_sockfd(-1){ 14 15 } 16 //1. Create socket 17 bool Socket(){ 18 //Socket (address domain, socket type, protocol type); 19 _sockfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); 20 if(_sockfd<0){ 21 perror("socket error"); 22 return false; 23 } 24 return true; 25 } 26 27 //2. Bind address information for socket 28 bool Bind(const std::string &ip,uint32_t port){ 29 //(1). Define IPv4 address structure 30 struct sockaddr_in addr; 31 addr.sin_family=AF_INET;//The address field is used to indicate to the bind interface that this is an ipv4 address structure 32 addr.sin_port=htons(port);//htons converts a 2-byte host byte order integer to a network byte order integer 33 addr.sin_addr.s_addr=inet_addr(ip.c_str());//IP address of network byte order 34 /* 35 //bind Assignment information of three parameters of the interface 36 struct sockaddr_in{ 37 sa_family_t sin_family; 38 in_port_t sin_port; 39 struct in_addr{ 40 in_addr_t _addr; 41 }sin_addr; 42 } 43 */ 44 //(2). Binding address 45 socklen_t len=sizeof(struct sockaddr_in); 46 //Bind (descriptor, uniform address structure, sockaddr *, address information length) 47 int ret=bind(_sockfd,(struct sockaddr*)&addr,len); 48 if(ret<0){ 49 perror("bind error"); 50 return false; 51 } 52 return true; 53 } 54 55 //3. Send data 56 bool Send(const std::string &data,const std::string &ip,uint16_t port){ 57 //SendTo (descriptor, data, length, options, peer address, address length) 58 //(1). Address structure of ipv4 that defines peer address information 59 struct sockaddr_in addr; 60 addr.sin_family=AF_INET;//The address field is used to indicate to the bind interface that this is an ipv4 address structure 61 addr.sin_port=htons(port);//htons converts a 2-byte host byte order integer to a network byte order integer 62 addr.sin_addr.s_addr=inet_addr(ip.c_str());//IP address of network byte order 63 //(2). Send data to this address 64 int ret; 65 socklen_t len=sizeof(struct sockaddr_in); 66 ret=sendto(_sockfd,data.c_str(),data.size(),0,(struct sockaddr*)&addr,len); 67 if(ret<0){ 68 perror("sendto error"); 69 return false; 70 } 71 return true; 72 } 73 74 //4. Send data 75 //Input parameters use const references 76 //Output parameters use pointers 77 //Use reference for input and output lines 78 bool Recv(std::string *buf,std::string *ip=NULL,uint16_t *port=NULL){ 79 //Recvfrom (descriptor, buffer, data length, options, peer address, address length) 80 struct sockaddr_in addr;//Used to obtain sender address information 81 socklen_t len=sizeof(struct sockaddr_in);//Specify the address length and get the actual address length 82 int ret; 83 char tmp[4096]={0};//A buffer used temporarily to hold data 84 ret=recvfrom(_sockfd,tmp,4096,0,(struct sockaddr*)&addr,&len); 85 if(ret<0){ 86 perror("recvfrom error"); 87 return -1; 88 } 89 buf->assign(tmp,ret);//Apply for ret size space for buf and copy ret length data from tmp 90 //For the sake of flexible interface, if the user does not want to obtain the address information, it will not be converted 91 Only when the user wants to get the address, the buffer is passed in, and we write the data in 92 if(ip!=NULL){ 93 *ip=inet_ntoa(addr.sin_addr);//Converts the network byte order integer IP address to a string address and returns 94 } 95 if(port!=NULL){ 96 *port=ntohs(addr.sin_port); 97 } 98 return true; 99 } 100 101 //5. Close the socket 102 void Close(){ 103 close(_sockfd); 104 _sockfd=-1; 105 return; 106 } 107 private: 108 //Socket descriptor throughout the full text 109 int _sockfd; 110 }; 111 112 #define CHECK_RET(q) if((q)==false){return -1;} 113 //If the client wants to send data to the server, it needs to know the address information of the server 114 Therefore, the address information of the server is passed in through the program running parameters 115 int main(int argc,char *argv[]){ 116 if(argc!=3){//Indicates the number of parameters. See whether the input parameter is 3 117 printf("em: ./udp_cli 192.168.122.132 9000\n"); 118 return -1; 119 120 } 121 122 //argv[0]=./udp_cli 123 //argv[1]=192.168.122.132 124 //argv[2]=9000 125 std::string ip_addr=argv[1];//Server address information 126 uint16_t port_addr=atoi(argv[2]); 127 UdpSocket sock; 128 CHECK_RET(sock.Socket());//Create socket 129 //CHECK_RET(sock.Bind());// Binding address information 130 while(1){ 131 //Get a standard input data and send it 132 std::cout<<"client say: "; 133 fflush(stdout); 134 std::string buf; 135 std::cin>>buf;//Get standard input data 136 sock.Send(buf,ip_addr,port_addr);//Sends buf data to the specified host process 137 138 buf.clear();//Empty buf buffer 139 sock.Recv(&buf);//Because the client itself knows the address of the server, it does not need to obtain it in the 140 std::cout<<"server say: "<<buf<<std::endl; 141 } 142 sock.Close(); 143 return 0; 144 }
TCP programming process: connection oriented, reliable transmission, byte stream oriented, UDP is the opposite, but both are (duplex communication)
Server:
1. Create socket -- create socket structure
2. Bind the address information for the socket (tell the operating system which data is put into my socket buffer and which source address information is used for sending data)
3. Start listening (a link needs to be established before communication at both ends of TCP - ensure that both sides of the communication have the ability to receive / send data; the process of establishing a connection is completed by the operating system, and the user does not need to care; starting listening is equivalent to telling the operating system that it can start receiving the connection request of the client)
(1) the socket created by the service can receive the connection request from the client
(2) when the client connection request arrives, the server will create a separate socket for the client
Description in socket structure (source IP / source port / peer IP / peer port / protocol...); These descriptions indicate that the socket is used specifically to communicate with the client
The server will create a socket for each client to communicate with the client (different from UDP)
The earliest socket creation: listening socket -- like door greeting -- always only receives connection requests from clients
Create a new socket: the communication socket -- subsequent data communication with the client -- is like a one-to-one waiter communicating with the client. How many clients means how many socket structures correspond to them
4. Get the operation handle descriptor of the new socket in the server program
Because subsequent communication with this client is completed through this operation handle
The earliest socket descriptor created -- the operation handle is only used to establish a connection and obtain a new connection
5. Sending and receiving data: because TCP socket describes both the source end and the opposite end, it is not necessary to obtain / specify the address information of the opposite end when sending and receiving data. (different from UDP)
6. Close socket: release resources
If the UDP server does not exist, it can still send data, and TCP directly rejects the connection (different from UDP)
client:
1. Create socket
2. Binding address information (not recommended)
3. Send a connection request to the server
4. Sending and receiving data
5. Close the socket
TCP client and server processes:
Client: create socket, describe address information, initiate connection request, connect successfully, send and receive data, close
Server: create a socket, describe the address information, start listening, receive connection requests, create a new socket, obtain the new socket descriptor, communicate with the client through this descriptor, and close.
Introduction to TCP programming socket interface:
1. Create socket: int socket(int domain, int type, int protocol); (AF_INET,SOCK_STREAM -- streaming socket, IPPROTO_TCP)
2. Binding address information: int bind (int sockfd,syruct sockaddr *addr,socklen_t len); struct sockaddr_in;
3. The server starts listening: int listen(int sockfd,int backlog)--- Tell the operating system to start receiving connection requests
backlog: determines the number of client connection requests that the server can receive at the same time - the maximum number of nodes,
However, it does not determine how many client parameters the server can receive.
In case of a network attack: SYN flooding attack: malicious hosts constantly send a large number of connection requests to the server host
If the server establishes a socket for each connection request, the resources will be exhausted and the server will crash
Therefore, the server has a connection pending queue; Store the newly created socket node for connection request; The backlog parameter determines the maximum number of nodes in the queue; If queue slows down, and if new connection requests arrive, subsequent requests are discarded.
4. Get the operation handle of the new socket: take a socket from the pending queue of the socket specified by the kernel and return the operation handle
int accept(int sockfd,struct sockaddr *addr,socklen_t *len);
sockfd: listening socket -- specifies which socket in the pending queue to get
Addr: obtain a socket, which communicates with the specified client, and obtain the address information of the client through addr
len: input / output type parameters --- specify the desired length of address information and return the actual address length
Return value: if successful, the descriptor of the newly obtained socket --- operation handle is returned
5. Communicate with the specified client through the newly obtained socket operation handle (descriptor returned by accept)
Received data: ssize_t recv(int sockfd,char *buf,int len,int flag); Return value: successfully returns the actual read data length; When the connection is disconnected, it returns 0; Reading failed, return - 1--- The TCP connection is disconnected, just like the pipeline reading data, all write segments are closed, and the reader returns 0
Send data: ssize_t send(int sockfd,char *data,int len,int flag); Return value: the length of the actually sent data is successfully returned; Failure returns - 1; If the connection is disconnected, an exception is triggered
6. Close socket: release resource int close (int fd)
7. The client sends a connection request to the server
int connect(int sockfd,int sockaddr *addr,socklen_t len);
sockfd: client socket --- if the address is not bound, the operating system will select the appropriate source address for binding
addr: server address information -- struct sockaddr_in; The address information will also be described in the socket after connect ing
len: length of address information
Byte order conversion interface:
uint6_t htons(uint16_t port);//2 bytes of data
uint6_t ntohs(uint16_t port);// Host byte order and network byte order
uint32_t htonl(uint32_t port);//4 bytes of data
uint32_t ntohl(uint32_t port);// Host byte order and network byte order
in_addr_t inet_addr(char *ip);// Convert dotted decimal string IP address to network byte order integer IP address
char *inet_ntoa(struct in_addr addr);// Convert network byte order integer IP address to dotted decimal string
int inet_pton(int domain,char *ip,void *ip);// String address translation, network byte order, integer address, domain address field
int inet_ntop(int domain,void *ip,char *ip,int len);// Convert network byte order integer IP address to dotted decimal string
The implementation code is as follows: including tcpsocket hpp
1 #include <cstdio> 2 #include <unistd.h> 3 #include <string.h> 4 #include <netinet/in. h> / / SOCKADDR structure / IPPROTO_UDP 5 #include <arpa/inet. h> / / contains some interfaces for byte order conversion 6 #include <sys/socket. h> / / socket interface header file 7 #include <iostream> 8 #include <stdlib. h> / / ATOI interface 9 //Encapsulate and implement a tcpsocket class to provide a simple interface to the outside world 10 //The tcp communication program can be established by instantiating a tcpsocket object 11 #define BACKLOG 10 12 #define CHECK_RET(q) if((q)==false){ return -1;} 13 class TcpSocket 14 { 15 public: 16 TcpSocket():_sockfd(-1){ 17 18 } 19 //1. Create socket 20 bool Socket(){ 21 //Socket (address domain, socket type, protocol type) 22 _sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 23 if(_sockfd<0){ 24 perror("socket create error"); 25 return false; 26 } 27 return true; 28 } 29 void Addr(struct sockaddr_in *addr,const std::string &ip,uint16_t port){ 30 addr->sin_family=AF_INET; 31 addr->sin_port=htons(port); 32 inet_pton(AF_INET,ip.c_str(),&(addr->sin_addr.s_addr)); 33 } 34 //2. Binding address information 35 bool Bind(const std::string &ip,const uint16_t port){ 36 //(1) Define IPv4 address structure 37 struct sockaddr_in addr; 38 Addr(&addr,ip,port); 39 socklen_t len=sizeof(struct sockaddr_in); 40 int ret=bind(_sockfd,(struct sockaddr*)&addr,len); 41 if(ret<0){ 42 perror("bind error"); 43 return false; 44 } 45 return true; 46 } 47 //3. The server starts listening 48 bool Listen(int backlog=BACKLOG){ 49 //Listen (descriptor, number of concurrent connections at the same time); 50 int ret=listen(_sockfd,backlog); 51 if(ret<0){ 52 perror("listen error"); 53 return false; 54 } 55 return true; 56 } 57 //4. The client initiates a connection request 58 bool Connect(const std::string &ip, const uint16_t port){ 59 //(1) Define the IPv4 address structure and give the server address information 60 struct sockaddr_in addr; 61 Addr(&addr,ip,port); 62 //(2) Send a request to the server 63 //(3) Conect (client descriptor, server address information, address length) 64 socklen_t len=sizeof(struct sockaddr_in); 65 int ret=connect(_sockfd,(struct sockaddr*)&addr,len); 66 if(ret<0){ 67 perror("connect error"); 68 return false; 69 } 70 return true; 71 } 72 //5. The server obtains the new connection 73 bool Accept(TcpSocket *sock,std::string *ip=NULL,uint16_t *port=NULL){ 74 //Accept (listening socket, peer address information, address information length) returns a new descriptor 75 struct sockaddr_in addr; 76 socklen_t len=sizeof(struct sockaddr_in); 77 //Get the new socket and the corresponding peer address information of the socket 78 int clisockfd=accept(_sockfd,(struct sockaddr*)&addr,&len); 79 if(clisockfd<0){ 80 perror("accept error"); 81 return false; 82 } 83 84 //Assign a value to the descriptor of this object -- assign a value to the descriptor of the new socket 85 Subsequent communication with the client can be completed through this object 86 sock->_sockfd=clisockfd;//The user passed in a pointer to the Tcpsocket object 87 if(ip!=NULL){ 88 *ip=inet_ntoa(addr.sin_addr);//Converts the network byte order integer IP address to a string address and returns 89 } 90 if(port!=NULL){ 91 *port=ntohs(addr.sin_port); 92 } 93 return true; 94 } 95 //6. Send data 96 bool Send(const std::string &data){ 97 //Send (descriptor, data, data length, option parameter) 98 int ret=send(_sockfd,data.c_str(),data.size(),0); 99 if(ret<0){ 100 perror("send error"); 101 return false; 102 } 103 return true; 104 } 105 //7. Receive data 106 bool Recv(std::string *buf){ 107 //Recv (descriptor, buffer, data length, option parameters) 108 char tmp[4096]={0}; 109 int ret=recv(_sockfd,tmp,4096,0); 110 if(ret<0){ 111 perror("recv error"); 112 return false; 113 }else if(ret==0){ 114 printf("connection break\n"); 115 return false; 116 } 117 buf->assign(tmp,ret);//Copy ret size data from tmp to buf 118 return true; 119 } 120 //8. Close the socket 121 bool Close(){ 122 close(_sockfd); 123 _sockfd=-1; 124 } 125 private: 126 int _sockfd; 127 };
tcp_cli.cpp
1 #include <iostream> 2 #include "tcpsocket.hpp" 3 #include <stdlib.h> 4 5 //Using encapsulated Tcpsocket class instantiation object to implement tcp server program 6 7 int main(int argc,char *argv[]){ 8 if(argc!=3){//Indicates the number of parameters. See whether the input parameter is 3 9 printf("em: ./tcp_cli 192.168.122.132 9000--Address of service binding\n"); 10 return -1; 11 } 12 std::string ip=argv[1]; 13 uint16_t port =atoi(argv[2]);//stoi converts strings to numbers 14 15 TcpSocket cli_sock; 16 //Create socket 17 CHECK_RET(cli_sock.Socket()); 18 //Binding address information (not recommended) 19 //CHECK_RET(cli_sock.Bind(ip,port)); 20 //Send a request to the server 21 CHECK_RET(cli_sock.Connect(ip,port)); 22 //Cyclic transceiver data 23 while(1){ 24 printf("client say:"); 25 fflush(stdout); 26 std::string buf; 27 std::cin>>buf; 28 29 //Because the client does not have files for multiple sockets, it is OK to exit directly in case of an error in the current socket 30 //When the process exits, it will release resources and close the socket 31 CHECK_RET(cli_sock.Send(buf)); 32 buf.clear(); 33 CHECK_RET(cli_sock.Recv(&buf)); 34 printf("server say:%s\n",buf.c_str()); 35 } 36 cli_sock.Close(); 37 return 0; 38 } ~
tcp_srv.cpp
1 #include <iostream> 2 #include <stdlib.h> 3 #include "tcpsocket.hpp" 4 5 6 //Using encapsulated Tcpsocket class instantiation object to implement tcp server program 7 8 int main(int argc,char *argv[]){ 9 if(argc!=3){//Indicates the number of parameters. See whether the input parameter is 3 10 printf("em: ./tcp_srv 192.168.122.132 9000\n"); 11 return -1; 12 } 13 std::string ip=argv[1]; 14 uint16_t port =atoi(argv[2]);//stoi converts strings to numbers 15 16 TcpSocket lst_sock; 17 CHECK_RET(lst_sock.Socket());//Create socket 18 CHECK_RET(lst_sock.Bind(ip,port));//Binding address information 19 CHECK_RET(lst_sock.Listen());//Start listening 20 while(1){ 21 TcpSocket cli_sock; 22 std::string cli_ip; 23 uint16_t cli_port; 24 //accept class member function, private member used_ sockfd is lst_ Private member of sock 25 cli_sock The address is passed in to obtain accept Communication socket descriptor returned by interface 26 bool ret=lst_sock.Accept(&cli_sock,&cli_ip,&cli_port);//Get new socket 27 if(ret==false){ 28 //Failed to get a new connection. You can continue to get the next one again 29 continue; 30 } 31 std::string buf; 32 if( cli_sock.Recv(&buf)==false){ 33 34 cli_sock.Close();//Error in receiving data from communication socket. Communication socket is closed 35 continue; 36 } 37 printf("client:[%s:%d] say:%s\n",&cli_ip[0],cli_port,&buf[0]); 38 std::cout<<"server say:"; 39 fflush(stdout); 40 buf.clear(); 41 std::cin>>buf; 42 if(cli_sock.Send(buf)==false){ 43 cli_sock.Close(); 44 continue; 45 } 46 } 47 lst_sock.Close(); 48 return 0; 49 } ~
Why can the TCP server only communicate with one client once and not continuously-- Process blocking
1. Server program blocking location: accept to obtain a new connection
2. Server program blocking location: recv/send at the communication with the client. If there is no data in the receiving buffer, the recv blocking solution
while(1){
1. Get new connection -- accept interface is a blocking function -- if there is no new connection, block and wait
2. Communicate with the client through a new connection
ssize_t ret=recv();-- receive data
ssize_t ret=send();-- send data
}
Take an example to illustrate the process of process blocking:
Why can the TCP server only communicate with one client once and not continuously? Solutions:
To prevent process blocking, it is necessary to ensure that an execution flow is only responsible for one function. An execution flow only obtains a new connection. When the new connection is successful, it creates a new execution flow to communicate with the client. Multi execution flow solution (multi process and multi thread)
Multi process: more stable
1. The parent process creates a child process with unique data, each with a cli_sock; However, the child process passes through cli_sock communication, but the parent process does not need it, so the parent process closes its cli_sock;
2. The parent process should wait for the child process to exit to avoid zombie processes; In order that the parent process is only responsible for obtaining new connections, the callback waiting is customized for SIGCHLD signal processing.
Orphan process: the parent process exits before the child process. The child process becomes an orphan process and runs in the background. The parent process becomes init process 1
Zombie process: the child process exits before the parent process. When the child process exits, the operating system sends a SIGCHLD signal to the parent process to notify the parent process. Your child process exits. The processing method is ignore. Therefore, the parent process does not pay attention to the exit state of the child process, and the child process becomes rigid
1 #include <iostream> 2 #include <stdlib.h> 3 #include "tcpsocket.hpp" 4 #include <signal.h> 5 #include <sys/wait.h> 6 7 //Using encapsulated Tcpsocket class instantiation object to implement tcp server program 8 W> 9 void sigcb(int signo){ 10 //When the child process exits, it will send a sigchld signal to the parent process to call back this function, 11 //The return value of waitpid > 0 indicates that an exiting child process has been processed 12 //Waitpid < = 0 indicates that there are no child processes exiting 13 while(waitpid(-1,0,WNOHANG)>0);//A callback loop will handle all the child processes that exit 14 } 15 int main(int argc,char *argv[]){ 16 if(argc!=3){//Indicates the number of parameters. See whether the input parameter is 3 17 printf("em: ./tcp_srv 192.168.122.132 9000\n"); 18 return -1; 19 } 20 std::string ip=argv[1]; 21 uint16_t port =atoi(argv[2]);//stoi converts strings to numbers 22 23 signal(SIGCHLD,sigcb);//If a child process exits, it will receive SIGCHLD and call back sigcb 24 TcpSocket lst_sock; 25 CHECK_RET(lst_sock.Socket());//Create socket 26 CHECK_RET(lst_sock.Bind(ip,port));//Binding address information 27 CHECK_RET(lst_sock.Listen());//Start listening 28 while(1){ 29 TcpSocket cli_sock; 30 std::string cli_ip; 31 uint16_t cli_port; 32 bool ret=lst_sock.Accept(&cli_sock,&cli_ip,&cli_port);//Get new socket 33 if(ret==false){ 34 continue; 35 } 36 printf("new connnect:[%s:%d]\n",cli_ip.c_str(),cli_port); 37 //--------------------------------------------------------------- 38 pid_t pid=fork(); 39 if(pid==0){//Child processes copy parent processes -- all data -- code sharing 40 41 //Let the child process process communicate with the client 42 while(1){ 43 std::string buf; 44 if( cli_sock.Recv(&buf)==false){ 45 46 cli_sock.Close();//Error in receiving data from communication socket. Communication socket is closed 47 exit(0); 48 } 49 printf("client:[%s:%d] say:%s\n",&cli_ip[0],cli_port,&buf[0]); 50 std::cout<<"server say:"; 51 fflush(stdout); 52 buf.clear(); 53 std::cin>>buf; 54 if(cli_sock.Send(buf)==false){ 55 cli_sock.Close(); 56 exit(0); 57 } 58 } 59 cli_sock.Close(); 60 exit(0); 61 } 62 //The parent-child process data is unique and will have cli_sock, but the parent process does not communicate 63 cli_sock.Close();//This shutdown has no impact on the child process, because each has a copy of the data to avoid resource leakage 64 wait(NULL);//Wait for the child process to exit to prevent zombie processes 65 } 66 lst_sock.Close(); 67 return 0; 68 }
Corpse process. The parent process needs to wait for the child process, obtain the return value and release the child process resources.
Multithreading: more flexible, (the cost of using threads is low, and the cost of resources, scheduling, creation and destruction)
1. The main thread obtains a new connection and then creates a new thread to communicate with the client, but the socket descriptor needs to be passed into the thread execution function
2. However, when this descriptor is passed in, the address of the local variable cannot be used (the space of the local variable will be released after the loop is completed). The value of the descriptor or the new object can be passed in
3. In C + +, there are many restrictions on strong type conversion and passing data values as pointers. Try to overcome them.
4. Cli is not applicable in the main thread_ Sock, but cli cannot be closed_ Sock, because resources are shared between threads, one thread is released and the other thread cannot be used.
cli_ The sock is an object instantiated by the TcpSocket class_ sock_fd is cli_ A member variable in the socket -- used to save the file descriptor returned by creating the socket
cli_sock.Recv(buf) receives data, and recv uses cli internally_ sockfd of sock receives data
1 #include <iostream> 2 #include <stdlib.h> 3 #include "tcpsocket.hpp" 4 #include <sys/wait.h> 5 #include <pthread.h> 6 7 //Using encapsulated Tcpsocket class instantiation object to implement tcp server program 8 9 void *thr_start(void *arg){ 10 long fd=(long)arg; 11 TcpSocket cli_sock; 12 cli_sock.SetFd(fd); 13 while(1){ 14 std::string buf; 15 if( cli_sock.Recv(&buf)==false){ 16 17 cli_sock.Close();//Error in receiving data from communication socket. Communication socket is closed 18 pthread_exit(NULL);//Thread exit, exit(0) process exit 19 } 20 printf("client:say:%s\n",&buf[0]); 21 std::cout<<"server say:"; 22 fflush(stdout); 23 buf.clear(); 24 std::cin>>buf; 25 if(cli_sock.Send(buf)==false){ 26 cli_sock.Close(); 27 pthread_exit(NULL); 28 } 29 } 30 return NULL; 31 cli_sock.Close(); 32 } 33 int main(int argc,char *argv[]){ 34 if(argc!=3){//Indicates the number of parameters. See whether the input parameter is 3 35 printf("em: ./tcp_srv 192.168.122.132 9000\n"); 36 return -1; 37 } 38 std::string ip=argv[1]; 39 uint16_t port =atoi(argv[2]);//stoi converts strings to numbers 40 41 TcpSocket lst_sock; 42 CHECK_RET(lst_sock.Socket());//Create socket 43 CHECK_RET(lst_sock.Bind(ip,port));//Binding address information 44 CHECK_RET(lst_sock.Listen());//Start listening 45 while(1){ 46 TcpSocket cli_sock; 47 std::string cli_ip; 48 uint16_t cli_port; 49 //accept class member function, private member used_ sockfd is lst_ Private member of sock 50 cli_sock The address is passed in to obtain accept Communication socket descriptor returned by interface 51 bool ret=lst_sock.Accept(&cli_sock,&cli_ip,&cli_port);//Get new socket 52 if(ret==false){ 53 //Failed to get a new connection. You can continue to get the next one again 54 continue; 55 } 56 printf("new connnect:[%s:%d]\n",cli_ip.c_str(),cli_port); 57 //---------------------------------------------------------------------- 58 pthread_t tid; 59 //The communication socket is passed to the thread as a parameter to let the thread communicate with the client 60 //cli_sock is a local variable -- the resource will be released after the loop is completed 61 pthread_create(&tid,NULL,thr_start,(void*)cli_sock.GetFd());//Create thread 62 pthread_detach(tid);//Do not care about the return value of the thread, separate the thread, and then automatically release the resources after exiting 63 //The main thread cannot close cli_sock socket, because multithreads share descriptors 64 } 65 lst_sock.Close(); 66 return 0; 67 }
The performance of connection disconnection at the sender and receiver (the same as the pipeline read-write characteristics):
1. Receiving end: if the connection is disconnected, recv returns 0; Conversely, if recv returns 0, it indicates that the connection is disconnected (socket write end is closed - duplex communication)
2. Sender: if the connection is disconnected, send triggers an exception, causing the process to exit
The Conduit:
If all the read ends of the pipeline are closed and writing continues, a SIGPIPE exception will be triggered
All write ends of the pipeline are closed, and 0 is returned when reading is continued
Summary:
1.udp programming process and interface:
Client: socket/sendto/recvfrom/close
Server: socket/bind/recvfrom/sendto/close
2.tcp programming process and interface:
Client: socket/connect/send/recv/close
Server: socket/bind/listen/accept/recv/send/close
3. Byte order conversion interface:
htons/ntohs/htonl/ntohl/inet_addr/inet_ntoa/inet_ntop/inet_pton
4. Multi execution flow tcp server process
Multi execution flow idea (multi process, multi thread)