Introduction to Socket (excerpted from Baidu Encyclopedia)

describe

Two programs on the network exchange data through a two-way communication connection, one end of which is called a socket. At least one pair of sockets is required to establish network communication connections.

Socket nature is programming interface (API), TCP/IP encapsulation, TCP/IP also to provide programmers to do network development for the interface, this is socket programming interface; HTTP is a car that provides a concrete form for encapsulating or displaying data; Sockets are engines that provide network communication capabilities.

When the connection is successful, both ends of the application program will generate a Socket instance, and operate the instance to complete the required session. Sockets are equal to each other for a network connection, there is no difference between levels on the server side and on the client side. Both sockets and ServerSockets do their work through the SocketImpl class and its subclasses.

The connection process

The connection process between sockets can be divided into three steps, depending on how the connection is initiated and to which destination the local socket is connecting: server listening, client request, and connection confirmation.

(1) Server monitoring: the server socket does not locate the specific client socket, but is in the state of waiting for connection and monitors the network status in real time.

(2) Client request: it refers to the connection request made by the client socket, and the target to be connected is the server socket. To do this, the client-side socket must first describe the socket of the server to which it is connecting, specifying the address and port number of the server-side socket, and then make a connection request to the server-side socket.

(3) Connection confirmation: when the server socket listens to or receives the connection request of the client socket, it responds to the request of the client socket, establishes a new thread, and sends the description of the server socket to the client. Once the client confirms the description, the connection is established. The server socket continues to listen, receiving connection requests from other client sockets.

IOS writes a native socket

1. Import header files and macro definitions
#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>//htons: Converts an unsigned short host value to network byte order (big-endian, little-endian)#define SocketPort htons(8040) // Port//inet_addr is a computer function that converts a dotted decimal IP address to a long integer#define SocketIP inet_addr("127.0.0.1") // IP
Copy the code
2. Create a socket

Function prototype:

int socket(int domain, int type, int protocol);

The function uses:

@property (nonatomic, assign) int clinenId; _clinenId = socket(AF_INET, SOCK_STREAM, 0);if (_clinenId == -1) {
    NSLog(@"Failed to create socket");
    return;
}
Copy the code

Parameter description: domain: indicates the protocol domain, also called the protocol family. Common protocol families include *AF_INET(ipv4), AF_INET6(ipv6), *AF_LOCAL (or AF_UNIX, Unix domain Socket), and AF_ROUTE. The protocol family determines the address type of the socket, and the corresponding address must be used in communication. For example, AF_INET determines the combination of ipv4 address (32-bit) and port number (16-bit), and AF_UNIX determines an absolute pathname as the address.

Type: indicates the Socket type. Common socket types include SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_PACKET, and SOCK_SEQPACKET. A stream Socket (SOCK_STREAM) is a connection-oriented Socket for connection-oriented TCP service applications. A datagram Socket (SOCK_DGRAM) is a connectionless Socket corresponding to a connectionless UDP service application.

Protocol: specifies a protocol. Common protocols include IPPROTO_TCP, IPPROTO_UDP, IPPROTO_STCP, and IPPROTO_TIPC, which correspond to TCP transport protocol, UDP transport protocol, STCP transport protocol, and TIPC transport protocol respectively.

Note: Type and protocol can not be combined at will. For example, SOCK_STREAM can not be combined with IPPROTO_UDP. When the third parameter is 0, the system automatically selects the default protocol corresponding to the second parameter type.

Return value: Returns the descriptor of the newly created socket on success or INVALID_SOCKET on failure (-1 on Linux failure). The socket descriptor is a value of type integer.

3. Create a connection

Function prototype:

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

The function uses: 3.1 Creating a socketAddr

/** __uint8_t sin_len; If there is no member, one of its bytes is incorporated into the sin_family member sa_family_t sin_family; Generally speaking, AF_INET (address family) PF_INET (protocol family) in_port_t sin_port; Struct in_addr sin_addr; // ip char sin_zero[8]; No practical point, just for the sake of */ struct sockaddr_in socketAddr; socketAddr.sin_family = AF_INET; // This is ipv4 socketAddr.sin_port = SocketPort; Struct in_addr socketIn_addr; socketIn_addr.s_addr = SocketIP; // socketAddr.sin_addr = socketIn_addr;Copy the code

3.2 the connection

    int result = connect(_clinenId, (const struct sockaddr *)&socketAddr, sizeof(socketAddr));
    if(result ! = 0) { NSLog(@"Failed to connect to socket");
        return;
    }
    NSLog(@"Connection successful");
Copy the code

Parameter description: sockfd: The descriptor that identifies a connected socket, which is the _clinenId we just created.

Addr: pointer to the address of the destination socket.

Addrlen: The length of the buffer to receive the return address.

Return value: 0 on success, non-0 on failure, GetLastError().

4. Send the MESSAGE

Function prototype:

ssize_t send(int sockfd, const void *buff, size_t nbytes, int flags);

The function uses:

    const char *msg = @"Message content".UTF8String; Ssize_t sendLen = send(self.clinenId, MSG, strlen(MSG), 0); NSLog(@"Sent :%ld bytes",sendLen);
Copy the code

Parameter description: sockfd: A description used to identify connected sockets. Buff: Buffer containing data to be sent. Nbytes: Indicates the length of the data in the buffer. Flags: call execution mode. Return value: The number of bytes sent is returned on success, or SOCKET_ERROR is returned on failure. A Chinese UTF8 encoding corresponds to three bytes. So it sends 3 by 4 bytes.

5. Receive data

Function prototype:

ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags);

The function uses:

uint8_t buffer[1024]; Is equivalent to / / recv ()readSsize_t recvLen = recv(self.clinenid, buffer, sizeof(buffer), 0); NSLog(@"Received :%ld bytes",recvLen);
    if (recvLen==0) {
        NSLog(@"This transmission length is 0. If it is 0 again, please check the connection."); } // Convert the received data to NSData *recvData = [NSData dataWithBytes:buffer Length :recvLen]; NSString *recvStr = [[NSString alloc] initWithData:recvData encoding:NSUTF8StringEncoding]; NSLog(@"% @",recvStr);
Copy the code

Parameter description: sockfd: A description used to identify connected sockets. Buff: Buffer containing data to be sent. Nbytes: Indicates the length of the data in the buffer. Flags: call execution mode. Return value: The number of bytes read in is returned on success, or SOCKET_ERROR on failure.

The complete code


Pragma mark - Creates a socket to establish a connection- (IBAction)socketConnetAction:(UIButton *)sender {// 1: create socket int socketID = socket(AF_INET, SOCK_STREAM, 0); self.clinenId= socketID;if (socketID == -1) {
        NSLog(@"Failed to create socket");
        return; } // 2: socket struct sockaddr_in socketAddr; socketAddr.sin_family = AF_INET; socketAddr.sin_port = SocketPort; struct in_addr socketIn_addr; socketIn_addr.s_addr = SocketIP; socketAddr.sin_addr = socketIn_addr; int result = connect(socketID, (const struct sockaddr *)&socketAddr, sizeof(socketAddr));if(result ! = 0) { NSLog(@"Connection failed");
        return;
    }
    NSLog(@"Connection successful"); // Call the method that starts receiving information //whileDispatch_async (dispatch_get_global_queue(0, 0), ^{[self recvMsg]; }); }#pragma mark - Send messages- (IBAction)sendMsgAction:(id) Sender {//3: Send a messageif (self.sendMsgContent_tf.text.length == 0) {
        return;
    }
    const char *msg = self.sendMsgContent_tf.text.UTF8String;
    ssize_t sendLen = send(self.clinenId, msg, strlen(msg), 0);
    NSLog(@"Send %ld bytes",sendLen);
}

#pragma mark - Accepts data- (void)recvMsg{// 4. Receive datawhile (1) {
        uint8_t buffer[1024];
        ssize_t recvLen = recv(self.clinenId, buffer, sizeof(buffer), 0);
        NSLog(@"Received :%ld bytes",recvLen);
        if (recvLen == 0) {
            continue;
        }
        // buffer -> data -> string
        NSData *data = [NSData dataWithBytes:buffer length:recvLen];
        NSString *str= [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"% @ % @" -- -,[NSThread currentThread],str); }}Copy the code

debugging

First run effect

Method one, simple and quick
  1. Open the command line tool and enter nC-LK 8040
  2. Click connect socket
  3. The command line tool randomly enters the character enter

    4. The simulator sends random input characters

Method 2: Write a local socket server

It sounds really awesome, but in fact, it’s about the same as the client. Bind (), listen(), and accept().

Header files, macros, properties

#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>

#define SocketPort htons(8040)
# define SocketIP inet_addr (" 127.0.0.1)"

@property (nonatomic, assign) int serverId;
@property (nonatomic, assign) int client_socket;
Copy the code
  1. The socket ()
    self.serverId = socket(AF_INET, SOCK_STREAM, 0);
    if (self.serverId == -1) {
        NSLog(@"Failed to create socket");
        return;
    }
    NSLog(@"Creating the socket succeeded");
Copy the code
  1. bind()
struct sockaddr_in socketAddr; socketAddr.sin_family = AF_INET; socketAddr.sin_port = SocketPort; struct in_addr socketIn_addr; socketIn_addr.s_addr = SocketIP; socketAddr.sin_addr = socketIn_addr; bzero(&(socketAddr.sin_zero), 8); // 2: bind socket int bind_result =bind(self.serverId, (const struct sockaddr *)&socketAddr, sizeof(socketAddr));
    if (bind_result == -1) {
        NSLog(@"Failed to bind socket");
        return;
    }

    NSLog(@"Binding socket succeeded");
Copy the code
  1. listen()
// 3: listen_result = listen(self.serverId, kMaxConnectCount);if (listen_result == -1) {
        NSLog(@"Listening failed.");
        return;
    }
    
    NSLog(@"Listening successful.");
Copy the code
  1. accept()
dispatch_async(dispatch_get_global_queue(0, 0), ^{ struct sockaddr_in client_address; socklen_t address_len; // accept function int client_socket = accept(self.serverId, (struct sockaddr *)&client_address, &address_len); self.client_socket = client_socket;if (client_socket == -1) {
            NSLog(@"Error accepting %u client",address_len);           
        }else{
            NSString *acceptInfo = [NSString stringWithFormat:@"Client in,socket:%d",client_socket];
            NSLog(@"% @",acceptInfo); / / receive messages [self receiveMsgWithClietnSocket: client_socket]; }});Copy the code
  1. recv()
whileChar buf[1024] = {0}; long iReturn = recv(clientSocket, buf, 1024, 0);if (iReturn>0) {
            NSLog(@"Message from the client."); NSData *recvData = [NSData dataWithBytes:buf length:iReturn]; NSString *recvStr = [[NSString alloc] initWithData:recvData encoding:NSUTF8StringEncoding]; NSLog(@"% @",recvStr);
            
        }else if (iReturn == -1){
            NSLog(@"Message read failed");
            break;
        }else if (iReturn == 0){
            NSLog(@"Client is gone.");
            
            close(clientSocket);
            
            break; }}Copy the code
  1. send()
    const char *msg = @"Send a message to the client".UTF8String;
    ssize_t sendLen = send(self.client_socket, msg, strlen(msg), 0);
    NSLog(@"Sent :%ld bytes",sendLen);
Copy the code
  1. close()
    int close_result = close(self.client_socket);
    
    if (close_result == -1) {
        NSLog(@"Failed to close the socket");
        return;
    }else{
        NSLog(@"Socket closed successfully");
    }
Copy the code

So this article ends here. The main purpose of writing this article is to deepen the impression and in-depth understanding of its implementation principle when learning GCDAsyncSocket in the future.