Networking programming in linux

Linux network programming

Socket: the port number is spliced to the IP address to form the socket.

Each TCP connection is uniquely determined by two endpoints (i.e. two sockets) at both ends of the communication

2. socket function

Create a socket and call the socket function

#include /* See NOTES */ #include int socket(int domain, int type, int protocol); // Return value: the file (socket) descriptor is returned successfully, and - 1 is returned on failure

Domain determines the characteristics of the communication, including the address format

Domain (domain) describe
AF_INET IPv4 Internet domain
AF_INET6 IPv6 Internet domain
AF_UNIX UNIX domain
AF_UPSPEC Not specified

Parameter type determines the type of socket and further determines the communication characteristics

Type describe
SOCK_DGRAM Fixed length, connectionless and unreliable message transmission UDP
SOCK_STREAM Ordered, reliable, bidirectional, connection oriented byte stream TCP
SOCK_SEQPACKET Fixed length, orderly, reliable, connection oriented message delivery
SOCK_RAW Datagram interface of IP protocol

The parameter protocol is usually 0, indicating that the default protocol is selected for a given domain and socket type.

Although a socket descriptor is essentially a file descriptor, not all functions whose parameters are file descriptors can receive socket descriptors.

3. shutdown function

Socket communication is bidirectional. You can use the shutdown function to disable I/O to a socket

#include int shutdown(int sockfd, int how); //Return value: 0 for success and - 1 for failure

Close can close a socket. Why use shutdown?

1. close releases the network endpoint only when the last active reference is closed, which means that if a socket is copied using dup/dup2, the socket will not be released until the last file descriptor that references it is closed.

As for when to call the shutdown() function, we will take file transfer as an example in the next section.

The difference between close()/closesocket() and shutdown()

To be exact, close() / closesocket() is used to close a socket, clear the socket descriptor (or handle) from memory, and then the socket can no longer be used, similar to fclose() in C language. After the application closes the socket, the connection and cache related to the socket also lose their significance, and TCP protocol will automatically trigger the operation of closing the connection.

Shutdown() is used to close the connection, not the socket. No matter how many times shutdown() is called, the socket still exists until close() / closesocket() is called to clear the socket from memory.

When close()/closesocket() is called to close the socket or shutdown() is called to close the output stream, FIN packets will be sent to the other party. The FIN packet indicates that the data transmission is completed, and the computer will know that there will be no more data transmission after receiving the FIN packet.

Читайте также:  Telnet kali linux установка

By default, close()/closesocket() will immediately send FIN packets to the network, regardless of whether there is data in the output buffer, while shutdown() will send FIN packets after the data in the output buffer has been transferred. This means that calling close()/closesocket() will lose the data in the output buffer, while calling shutdown() will not.

Disconnect procedure using shutdown

4. Byte order

When communicating with a process on the same computer, byte order is usually not considered. Byte order is a processor architecture feature used to indicate how bytes inside big data types like integers are sorted

Network byte order is big end mode

How to check whether your environment is big end mode or small end mode?

Use the union to test. According to the characteristics of the union, the size of the union is determined by the member variable that occupies the largest byte (byte alignment needs to be considered)

#include union bit< short n; char byte[2]; >; //Two byte alignment int main(int argc,char *argv[]) < union bit i; i.n = 0x1234; if (i.byte[0] == 0x34) // Low address data printf("little\n"); else printf("big\n"); return 0; >

5. Large and small end conversion

1. System call function conversion

#include uint32_t htonl(uint32_t hostlong); //Return value: 32-bit integer in network byte order uint16_t htons(uint16_t hostshort); //Return value: 16 bit integer in network byte order uint32_t ntohl(uint32_t netlong); //Return value: 32-bit integer in host byte order uint16_t ntohs(uint16_t netshort); //Return value: 16 bit integer in host byte order

h(host) stands for «host byte order»

n(network) stands for «network byte order»

2. Transform by yourself

uint32_t htonl32(uint32_t number) < uint32_t a = 0; a |= ((number >> 24) & 0xFF); //Move the highest byte to the lowest address a |= ((number > 8) & 0xFF00);// The middle two bytes are transposed a |= ((number uint16_t htons16(uint16_t number) < uint16_t a = 0; a |= ((number >> 8) & 0xFF); a |= ((number

6. Address format

An address identifies the socket endpoint of a specific communication domain, and the address format is related to the specific communication domain. In order to transfer different format addresses into socket function, the address will be converted into a general address structure sockaddr;

sockaddr universal address structure

typedef unsigned short sa_family_t struct sockaddr < sa_family_t sa_family; //Address family AF_ XXXX 2 bytes char sa_data[14]; //Variable length address contains IP address and port 14 bytes >;

IPV4 socket address structure sockaddr_in

struct sockaddr_in < sa_family_t sin_family; /* Address family */ //2 bytes in_port sin_port; /* Destination port number */ //2 bytes struct in_addr sin_addr; /* IP address*/ // 4 bytes /* Pad to size of `struct sockaddr'. */ unsigned char sin_zero[8];/*Fill byte*/ //8 bytes need to be cleared >; struct in_addr < unsigned int s_addr; >;

sockaddr and sockaddr_ The difference between in and out

sockaddr is general. When passing parameters to later functions, sockaddr is used_ In can be converted to sockaddr

Both are the same length, 16 bytes

sockaddr_in is the address form of socket in internet environment. So in network programming, we will focus on sockaddr_in structure, using sockaddr_in to create the required information, and finally use type conversion. Generally, SOCKADDR is used first_ After the value of the in variable is assigned, the function with SOCKADDR as the parameter is transferred after the mandatory type conversion: sockaddr_in is used for socket definition and assignment; SOCKADDR is used for function parameters.

Читайте также:  Linux ppc64le что это

7. Conversion of dot decimal IP to network byte order IP

Dot decimal, convert to 32-bit IP

1, inet_addr function
in_addr_t inet_addr(const char *cp); //cp dot decimal address //Returns the 32-bit address of the network byte order
2,inet_aton function
int inet_aton(const char *cp, struct in_addr *inp); //1 for success, 0 for failure, and - 1 for error
parameter describe
cp Dotted decimal address
inp The first address of the conversion result space stores the address of the variable of the conversion result
3,inet_pton function
int inet_pton(int af, const char *src, void *dst); //1 for success, 0 for failure, and - 1 for error
parameter describe
af IP address type AF_INET(IPV4) AF_INET6(IPV6)
src Dotted decimal address data
dst If the buffer used to store the conversion result is IPV4, it needs 4 bytes; IPV6 requires 16 bytes

32 bit IP to decimal

1,inet_ntoa function
#include #include #include char *inet_ntoa(struct in_addr in); //Returns the address of the dotted decimal address string
2,inet_ntop function
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); //Return value, success, return address string pointer, failure return NULL
parameter describe
af IP address type AF_INET(IPV4) AF_INET6(IPV6)
src Binary IP address of 32-bit network byte order
dst Buffer to hold dotted decimal strings
size dst buffer size, two constants IPV4: INET_ADDRSRTRLEN IPV6: INET6_ADDRSTRLEN

8. Associate socket with address bind (server)

It’s not much new to associate the socket of the client with an address. You can let the system choose a default address.

For a server, a well-known address needs to be associated with a server socket that receives client requests.

So bind is used on the server side

#include /* See NOTES */ #include int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); //Return value: 0 for success and - 1 for failure
parameter describe
sockfd socket descriptor
addr sockaddr filled with address family, IP address and port_ In structure, it needs to be converted to sockaddr when transferring parameters
addrlen Length of addr

There are some restrictions on the address being used

1. On the computer where the process is running, the specified address must be valid. You cannot specify the address of another machine

2. The address must match the format supported by the address family when the socket was created

3. The port in the address must be no less than 1024, unless the process has permission (root)

Recognized ports: from 0 to 1023
Ports less than 256 are reserved
Registration port: port number from 1024 to 49151
Dynamic and / or private ports: from 49152 to 65535. In theory, these ports should not be assigned to services. In fact, machines usually allocate dynamic ports from 1024.

4. Generally, only one socket endpoint can be bound to a given address (sockaddr)

int sock_fd = socket(AF_INET, SOCK_STREAM, 0); // IPV4 tcp struct sockaddr_in addr; memset(&addr, 0, sizeof(addr); addr.sin_family = AF_INET; //IPV4 needs to be consistent with the specification in socket addr.sin_addr = inet_addr("192.168.51.122"); addr.sin_port = 5050;//Greater than 1024 bind(sock_fd, (struct sockaddr*)&addr, sizeof(addr));

9. Connection request connect (client)

If you want to process a connection oriented network service (TCP), you need to establish a connection (three handshakes) between the process socket (client) that requests the service and the socket (server) that provides the service before you begin to exchange data

#include /* See NOTES */ #include int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); // Return value: 0 for success and - 1 for failure
parameter describe
sockfd socket descriptor
addr Filled with address family, server IP address, server port sockaddr_in structure, it needs to be converted to sockaddr when transferring parameters
addrlen Length of addr
Читайте также:  Virtualbox shared folders windows to linux

The address of sockaddr specified in connect is the server address we want to communicate with. Connect will bind a default address (native IP) to the caller, which is why the client does not need to use bind (TCP)

When trying to connect to the server, the connection may fail. These errors may be caused by some transient conditions.

Here’s how to deal with transient connect errors. If a server is running on a heavily loaded system, this error is likely to occur

Exponential compensation algorithm: if the call to connect fails, the process will sleep for a short period of time, and then enter the next cycle to try. The sleep time of each cycle increases exponentially until the maximum delay is about 2 minutes

#define MAXSLEEP 128 int connect_try(int sockfd, const strcut sockaddr *addr, socklen_t addrlen) < int num_sec; for(num_sec = 1; numsec return -1; //Timeout, return - 1 >

10. Listen to connection requests

The server calls the listen function to announce that it is willing to receive the connection request

#include /* See NOTES */ #include int listen(int sockfd, int backlog); //0 for success and - 1 for failure
parameter describe
sockfd The socket returned by the socket function
backlog The maximum number of connections allowed to wait in the queue before the accept reply is 128

11. Handle the client’s connection request accept (server)

Establish socket connection and handle single connection request

#include /* See NOTES */ #include int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); //The socket connected to the client is returned on success, and - 1 is returned on failure
parameter describe
sockfd Listening for socket descriptor for port
addr The client’s sockaddr information
addrlen sockaddr length

The file descriptor returned by accept is the socket descriptor, which connects to the client calling connect.

addr stores the information of the client to which connect is called, including address family, IP address and port. If the server doesn’t care, it can be set to NULL

If the server calls accept and there is no connection request, the server will block until a new request arrives.

In addition, the server can use poll or select to wait for a request to arrive. In this case, a socket with a waiting connection request will exist in a readable way

Network programming model based on TCP

The programming model above shakes hands three times and waves four times

TCP multi process / multi thread server model

TCP multi process server model

Advantages: security, process isolation, a process crash, will not lead to server crash

Disadvantages: it takes up a lot of resources

TCP multi thread server model

Advantages: less resources

Disadvantages: unsafe, threads use process resources, a thread crash will cause the whole process crash

Posted by JefferyZhou at May 16, 2021 — 3:54 PM Tag: socket Linux

Hot Categories

Hot Tags

  • Java × 8678
  • Python × 3398
  • Algorithm × 2157
  • Linux × 2069
  • Javascript × 1932
  • data structure × 1524
  • Spring × 1497
  • C++ × 1439
  • MySQL × 1163
  • Database × 1138
  • Front-end × 1057
  • Design Pattern × 1024

Источник

Оцените статью
Adblock
detector