Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to realize Socket Communication

2025-02-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article introduces the relevant knowledge of "how to achieve Socket communication". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

TCP/IP 、 UDP 、 Socket

You are not familiar with the words TCP/IP, UDP and Socket programming, are you? With the development of network technology, these words fill our ears. Then I would like to ask:

1. What is TCP/IP, UDP?

2. Where is Socket?

3. What is Socket?

4. Can you use them?

What is TCP/IP, UDP?

TCP/IP (Transmission Control Protocol/Internet Protocol), the transmission control protocol / internetwork protocol, is an industry standard protocol set designed for the wide area network (WANs).

UDP (User Data Protocol, user Datagram Protocol) is the protocol corresponding to TCP. It belongs to one of the TCP/IP protocol families.

Here is a diagram that shows the relationship between these protocols.

Figure 1

The TCP/IP protocol family includes the transport layer, the network layer and the link layer. Now you know the relationship between TCP/IP and UDP.

Where is Socket?

In figure 1, we don't see the shadow of Socket, so where is it? Still use the picture to speak, it is clear at a glance.

Figure 2

So Socket is here.

What is Socket?

Socket is the middle software abstraction layer for the communication between the application layer and the TCP/IP protocol family, and it is a group of interfaces. In the design pattern, Socket is actually a facade pattern, which hides the complex TCP/IP protocol family behind the Socket interface. For users, a simple set of interfaces is all, allowing Socket to organize the data to comply with the specified protocol.

Can you use them?

Our predecessors have done a lot for us, and the communication between networks is much easier, but after all, there is still a lot of work to be done. When I heard about Socket programming in the past, I thought it was a relatively advanced programming knowledge, but as long as I found out how Socket programming works, the mystery was lifted.

A scene in life. If you want to call a friend, dial first, and the friend will pick up the phone when he hears the ringtone, and then you and your friend will have a connection and can talk. When the exchange is over, hang up the phone and end the conversation. The scenes in life explain how this works. Maybe the TCP/IP protocol family was born in life, but not necessarily.

Figure 3

Let's start with the server side. The server initializes Socket, then binds to the port (bind), listen the port, calls accept blocking, and waits for the client to connect. At this point, if a client initializes a Socket and then connects to the server (connect), if the connection is successful, the connection between the client and the server is established. The client sends the data request, the server receives the request and processes the request, then sends the response data to the client, the client reads the data, finally closes the connection, and an interaction ends.

We are well aware of the value of information exchange, so how do processes communicate with each other in the network, such as how the browser process communicates with the web server when we open the browser to browse the web every day? When you chat with QQ, how does the QQ process communicate with the server or the QQ process where your friends are located? It all depends on socket? Then what is socket? What are the types of socket? There are also the basic functions of socket, which this article would like to introduce.

1. How do processes communicate in the network?

There are many ways of local interprocess communication (IPC), but they can be summarized into the following four categories:

Message delivery (pipeline, FIFO, message queue)

Synchronization (mutexes, condition variables, read-write locks, file and write record locks, semaphores)

Shared memory (anonymous and named)

Remote procedure calls (Solaris gate and Sun RPC)

But these are not the theme of this article! What we are going to discuss is how processes communicate with each other in the network. The first problem to solve is how to uniquely identify a process, otherwise communication is out of the question! It is possible to uniquely identify a process locally through the process PID, but this does not work in the network. In fact, the TCP/IP protocol family has helped us solve this problem. The "ip address" of the network layer can uniquely identify the host in the network, while the "protocol + port" of the transport layer can uniquely identify the application (process) in the host. In this way, the triple (ip address, protocol, port) can be used to identify the process of the network, and the process communication in the network can use this flag to interact with other processes.

Applications that use the TCP/IP protocol usually use the API: UNIX BSD's socket (socket) and UNIX System V's TLI (which has been eliminated) to communicate between network processes. At present, almost all applications use socket, and now it is the network age, where process communication is ubiquitous, which is why I say "everything is socket".

2. What is Socket?

We already know that processes in the network communicate through socket, so what is socket? Socket originated from Unix, and one of the basic philosophies of Unix/Linux is "everything is a file", which can be operated in the "Open open-> read and write write/read-> close close" mode. My understanding is that Socket is an implementation of this pattern, socket is a special file, and some socket functions operate on it (read / write IO, open, close), which we will introduce later.

The origin of the word socket

The first use in the field of networking was found in the literature IETF RFC33 published on February 12, 1970, written by Stephen Carr, Steve Crocker and Vint Cerf. According to the American Museum of computer History, Croker wrote: "Namespace elements can be called socket interfaces. A socket interface forms one end of a connection, and a connection can be completely defined by a pair of socket interfaces." The computer History Museum added: "this is about 12 years earlier than the definition of BSD's socket interface."

3. Basic operation of socket

Since socket is an implementation of the "open-write/read-close" pattern, socket provides functional interfaces for these operations. Let's take TCP as an example to introduce several basic socket interface functions.

3.1.The socket () function int socket (int domain, int type, int protocol)

The socket function corresponds to the opening operation of a normal file. The opening of a normal file returns a file description, while socket () is used to create a socket descriptor (socket descriptor) that uniquely identifies a socket. This socket description word is the same as the file description word, the subsequent operations are useful to it, take it as a parameter, through it to do some read and write operations.

Just as you can pass in different parameter values to fopen to open different files. When you create a socket, you can also specify different parameters to create different socket descriptors. The three parameters of the socket function are:

Domain: protocol domain, also known as protocol family (family). The commonly used protocol families are AF_INET, AF_INET6, AF_LOCAL (or AF_UNIX, Unix domain socket), AF_ROUTE and so on. The protocol family determines the address type of socket, and the corresponding address must be used in communication. For example, AF_INET decides to use the combination of ipv4 address (32-bit) and port number (16-bit), and AF_UNIX decides to use an absolute path name as the address.

Type: specifies the socket type. The commonly used socket types are SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_PACKET, SOCK_SEQPACKET, and so on (what are the types of socket? ).

Protocol: therefore, the name "thought" means to specify the agreement. The commonly used protocols are IPPROTO_TCP, IPPTOTO_UDP, IPPROTO_SCTP, IPPROTO_TIPC, etc., which correspond to TCP transport protocol, UDP transport protocol, STCP transport protocol, and TIPC transport protocol (I will discuss this protocol separately! ).

Note: the above type and protocol can not be combined at will, for example, SOCK_STREAM cannot be combined with IPPROTO_UDP. When protocol is 0, the default protocol corresponding to the type type is automatically selected.

When we call socket to create a socket, the returned socket description exists in the address family,AF_XXX space, but does not have a specific address. If you want to assign an address to it, you must call the bind () function, otherwise the system will automatically randomly assign a port when connect () and listen () are called.

3.2.The bind () function

As mentioned above, the bind () function assigns a specific address in an address family to socket. For example, the corresponding AF_INET and AF_INET6 assign a combination of ipv4 or ipv6 address and port number to socket.

Int bind (int sockfd, const struct sockaddr * addr, socklen_t addrlen)

The three parameters of the function are:

Sockfd: the socket description word, which is created by the socket () function and uniquely identifies a socket. The bind () function simply binds a name to the descriptor.

Addr: a const struct sockaddr * pointer to the protocol address to bind to sockfd. This address structure varies according to the address protocol family in which the socket is created, for example, ipv4 corresponds to:

Struct sockaddr_in {sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr;}; struct in_addr {uint32_t saddr;}

Ipv6 corresponds to:

Struct sockaddr_in6 {sa_family_t sin6_family; in_port_t sin6_port; uint32_t sin6_flowinfo; struct in6_addr sin6_addr; uint32_t sin6_scope_id;}; struct in6_addr {unsigned char s6_addr [16];}

The Unix domain corresponds to:

# define UNIX_PATH_MAX 108struct sockaddr_un {sa_family_t sun_family; char sun_ path [Unix _ PATH_MAX];}

Addrlen: corresponds to the length of the address.

Usually, when the server starts up, it will bind a well-known address (such as ip address + port number) to provide services, so that customers can connect to the server through it; while the client does not need to specify, the system automatically assigns a combination of port number and its own ip address. This is why bind () is usually called by the server before listen, but not by the client, but is randomly generated by the system when connect ().

Network byte order and host byte order

Host byte order is what we usually call large-end and small-end modes: different CPU have different types of byte order, which refers to the order in which integers are stored in memory, which is called host order. The definitions of Big-Endian and Little-Endian that reference the standard are as follows:

A) Little-Endian means that low-order bytes are placed on the low-address side of memory, while high-order bytes are placed on the high-address side of memory.

B) Big-Endian means that the high-order bytes are placed on the low address side of the memory, and the low-order bytes are placed on the high address side of the memory.

Network byte order: 4-byte 32 bit values are transmitted in the following order: first 0~7bit, then 8~15bit, then 16~23bit, and finally 24~31bit. This transmission order is called large-end byte order. Because all binary integers in the header of TCP/IP are required to be transmitted in this order in the network, it is also called network byte order. Byte order, as the name implies, is the order in which data of more than one byte type is stored in memory, and one byte of data is out of order.

So: when binding an address to socket, first convert the host byte order to the network byte order, instead of assuming that the host byte order uses the same Big-Endian as the network byte order. Because of this problem, there has been a murder! Because of this problem in the company project code, there are a lot of inexplicable problems, so please remember not to make any assumptions about the host byte order, be sure to convert it to network byte order and assign it to socket.

3.3.The listen (), connect () functions

As a server, after calling socket () and bind (), listen () will be called to listen to the socket, and if the client calls connect () to make a connection request, the server will receive the request.

Int listen (int sockfd, int backlog); int connect (int sockfd, const struct sockaddr * addr, socklen_t addrlen)

The first parameter of the listen function is the socket description word to listen for, 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, and the listen function turns the socket into a passive type, waiting for a connection request from the customer.

The first argument to the connect function is the client's socket description, the second is the server's socket address, and the third is the length of the socket address. The client establishes a connection to the TCP server by calling the connect function.

3.4.The accept () function

After the TCP server calls socket (), bind (), and listen () in turn, it listens for the specified socket address. After calling socket () and connect (), the TCP client sends a connection request to the TCP server. After the TCP server listens to the request, it calls the accept () function to receive the request, so the connection is established. After that, you can start the network Iamp O operation, which is similar to the read and write Imax O operation of ordinary files.

Int accept (int sockfd, struct sockaddr * addr, socklen_t * addrlen)

The first parameter of the accept function is the socket description word of the server, the second parameter is the pointer to struct sockaddr *, which returns the protocol address of the client, and the third parameter is the length of the protocol address. If the accpet succeeds, its return value is a completely new description word automatically generated by the kernel, representing the TCP connection to the returned customer.

Note: the first argument to accept is the server's socket description word, which is generated when the server starts calling the socket () function, which is called listening for the socket description word, while the accept function returns the connected socket description word. A server usually only creates a listener socket description, which exists throughout the server's lifetime. The kernel creates a connected socket description word for each client connection accepted by the server process. When the server finishes serving a client, the corresponding connected socket description word is closed.

3. 5, read (), write () and other functions

Everything is available only to Dongfeng, so the server has established a connection with the customer. You can call the network Imax O for read and write operations, that is, to achieve the communication between different processes in the network! There are several groups of network Icano operations:

Read () / write ()

Recv () / send ()

Readv () / writev ()

Recvmsg () / sendmsg ()

Recvfrom () / sendto ()

I recommend using the recvmsg () / sendmsg () function, which is the most generic Imax O function, and can actually replace all the other functions above with these two functions. Their statements are as follows:

# include ssize_t read (int fd, void * buf, size_t count); ssize_t write (int fd, const void * buf, size_t count); # include # include ssize_t send (int sockfd, const void * buf, size_t len, int flags); ssize_t recv (int sockfd, void * buf, size_t len, int flags) Ssize_t sendto (int sockfd, const void * buf, size_t len, int flags, const struct sockaddr * dest_addr, socklen_t addrlen); ssize_t recvfrom (int sockfd, void * buf, size_t len, int flags, struct sockaddr * src_addr, socklen_t * addrlen); ssize_t sendmsg (int sockfd, const struct msghdr * msg, int flags) Ssize_t recvmsg (int sockfd, struct msghdr * msg, int flags)

The read function is responsible for reading content from fd. When the read is successful, read returns the number of bytes actually read. If the returned value is 0, the end of the file has been read, and less than 0 indicates that an error has occurred. If the error is EINTR, it indicates that the read is caused by an interrupt, and if it is ECONNREST, there is a problem with the network connection.

The write function writes the nbytes byte contents of buf to the file descriptor fd. Returns the number of bytes written on success. Returns-1 on failure and sets the errno variable. In a network program, there are two possibilities when we write to a socket file descriptor. 1) the return value of write is greater than 0, indicating that some or all of the data has been written. 2) the returned value is less than 0, and an error occurs. We have to deal with it according to the type of error. If the error is EINTR, an interrupt error occurred while writing. If EPIPE indicates that there is a problem with the network connection (the other party has closed the connection).

I will not introduce these pairs of Imax O functions one by one, see the man documentation or baidu or Google. Send/recv will be used in the following examples.

3.6.The close () function

After the connection between the server and the client is established, some read and write operations will be carried out. When the read and write operation is completed, the corresponding socket description words will be closed, just like calling fclose to close the open file after the operation of the open file.

# include int close (int fd)

Close the default behavior of a TCP socket marks the socket as closed and then immediately returns to the calling process. This description can no longer be used by the calling process, that is, it can no longer be used as the first parameter of read or write.

Note: the close operation only causes the reference count of the corresponding socket description word to be-1. Only when the reference count is 0 will the TCP client be triggered to send a termination request to the server.

4. Detailed explanation of establishing connection by three-way handshake of TCP in socket

We know that tcp needs a "three-way handshake" to establish a connection, that is, to exchange three packets. The general process is as follows:

The client sends a SYN J to the server

The server responds to a SYN K to the client and acknowledges ACK Junction 1 to SYN J

The client sends an acknowledgement to the server to ACK Knowled1.

There is only a three-way handshake, but which functions of socket do this three-way handshake take place? Please take a look at the following picture:

Figure 1. TCP three-way handshake sent in socket

As can be seen from the figure, when the client calls connect, the connection request is triggered and the SYN J packet is sent to the server, and the connect enters the blocking state; the server listens to the connection request, that is, it receives the SYN J packet, and calls the accept function to receive the request to send SYN K, ACK Junction 1 to the client, and the accept enters the blocking state; after the client receives the SYN K, ACK Junction 1 from the server, connect returns and acknowledges the SYN K When the server receives ACK knot 1, accept returns. At this point, the three-way handshake is complete and the connection is established.

Summary: the client's connect returns on the second time of the three-way handshake, while the server's accept returns on the third time of the three-way handshake.

5. Detailed explanation of the four-way handshake release connection of TCP in socket

The above describes the establishment process of the three-way handshake of TCP in socket and the socket functions involved. Now let's introduce the process of releasing a connection with a four-way handshake in socket. Take a look at the following figure:

Figure 2. TCP four-way handshake sent in socket

The process shown is as follows:

An application process first calls close to actively close the connection, and then TCP sends a FIN M

After receiving the FIN M, the other end performs a passive shutdown to confirm the FIN. Its reception is also passed to the application process as a file Terminator, because the reception of FIN means that the application process can no longer receive additional data on the corresponding connection.

After a while, the application process that receives the file Terminator calls close to close its socket. This causes its TCP to also send a FIN N

TCP, the source and sender that received the FIN, confirms it.

So there is a FIN and ACK in each direction.

6. The following is an example of an implementation

First of all, give a screenshot of the implementation.

The server-side code is as follows:

# include "InitSock.h" # include # include using namespace std;CInitSock initSock; / / initialize Winsock library int main () {/ / create socket SOCKET sListen =:: socket (AF_INET, SOCK_STREAM, IPPROTO_TCP) / / used to specify the address format used by the socket. AF_INET / / is usually used to specify the socket type. For SOCK_DGRAM, it uses udp unreliable transmission / / with the type parameter, and specifies the protocol type to be used (when the socket type is specified, it can be set to 0 Because the default is UDP or TCP) if (sListen = = INVALID_SOCKET) {printf ("Failed socket ()\ n") Return 0;} / / populates the sockaddr_in structure, which is a structure / * struct sockaddr_in {short sin_family; / / address family (specified address format), set to AF_INET u_short sin_port; / / port number struct in_addr sin_addr; / / IP address char sin_zero [8] / / empty subsection, set to empty} * / sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons (4567); / / 1024-49151: the port number registered by ordinary users sin.sin_addr.S_un.S_addr = INADDR_ANY / / bind this socket to a local address if (:: bind (sListen, (LPSOCKADDR) & sin, sizeof (sin)) = = SOCKET_ERROR) {printf ("Failed bind ()\ n"); return 0 } / / enter listening mode / / 2 refers to the maximum number of outstanding connections allowed to remain in the listening queue if (:: listen (sListen, 2) = = SOCKET_ERROR) {printf ("Failed listen ()\ n"); return 0;} / / accept customer connection requests sockaddr_in remoteAddr in a loop Int nAddrLen = sizeof (remoteAddr); SOCKET sClient= 0; char szText [] = "TCP Server Demo!\ r\ n"; while (sClient==0) {/ / accepts a new connection / / ((SOCKADDR*) & remoteAddr) A pointer to the sockaddr_in structure to get the address sClient=:: accept (sListen, (SOCKADDR*) & remoteAddr, & nAddrLen) If (sClient = = INVALID_SOCKET) {printf ("Failed accept ()");} printf ("accept a connection:% s\ r\ n", inet_ntoa (remoteAddr.sin_addr)); continue;} while (TRUE) {/ / send data gets (szText) to the client :: send (sClient, szText, strlen (szText), 0); / / receive data from the client char buff [256]; int nRecv =: recv (sClient, buff, 256,0); if (nRecv > 0) {buff [nRecv] ='\ 0; printf ("received data:% s\ n", buff) }} / / close the connection with the client:: closesocket (sClient); / / close the listening socket:: closesocket (sListen); return 0;}

Client code:

# include "InitSock.h" # include # include using namespace std;CInitSock initSock; / / initialize the Winsock library int main () {/ / create sockets SOCKET s =: socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); if (s = = INVALID_SOCKET) {printf ("Failed socket ()\ n"); return 0 } / / you can also call the bind function here to bind a local address / / otherwise the system will automatically arrange / / fill in the remote address information sockaddr_in servAddr; servAddr.sin_family = AF_INET; servAddr.sin_port = htons (4567) / / Note: fill in the IP address of the machine where the server program (TCPServer program) is located / / if your computer is not connected to the Internet, use 127.0.0.1 directly to servAddr.sin_addr.S_un.S_addr = inet_addr ("127.0.0.1"). If (:: connect (s, (sockaddr*) & servAddr, sizeof (servAddr)) =-1) {printf ("Failed connect ()\ n"); return 0;} char buff [256]; char szText [256]; while (TRUE) {/ / receive data from the server int nRecv =: recv (s, buff, 256,0) If (nRecv > 0) {buff [nRecv] ='\ 0mm; printf ("received data:% s\ n", buff);} / / send data gets (szText) to the server; szText [255] ='\ 0mm;: send (s, szText, strlen (szText), 0) } / / close socket:: closesocket (s); return 0;}

Encapsulated InitSock.h

# include # pragma comment (lib, "WS2_32") / / Link to WS2_32.lib class CInitSock {public: CInitSock (BYTE minorVer = 2, BYTE majorVer = 2) {/ / initialize WS2_32.dll WSADATA wsaData; WORD sockVersion = MAKEWORD (minorVer, majorVer) If (:: WSAStartup (sockVersion, & wsaData)! = 0) {exit (0);} ~ CInitSock () {:: WSACleanup ();}}; this is the end of the introduction of "how to implement Socket Communication". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report