List of the journal

  1. About Socket, read my several articles enough (1)
  2. As for sockets, this article is enough (2) HTTP
  3. So you are such a Websocket

This article is the first in a series that introduces sockets

preface

As a professional iOS programmer who is not CS(Computer Science), he has very little knowledge about Computer networks.

The reason is simple: how can we grow if we only know how to use AFNetworking, Alamofire, etc., without a deeper understanding of the web?

What is a Socket

Socket is an abstract definition, our generalized computer network system has a 7-layer model

layer The OSI definition
7 The application layer
6 The presentation layer
5 The session layer
4 The transport layer
3 The network layer
2 Data link layer
1 The physical layer

Here, sockets represent layer 5 and 6, that is, the session layer, the presentation layer

The session layer is responsible for establishing the connection between the client and the server (generally called the one who initiates the connection actively is the client and the other is the server)

The presentation layer is responsible for data format transformation, encryption and decryption

See here, it is possible to have doubts, what is a socket?

In a broad sense (for all operating systems), a socket is a plain C header (.h) that defines data structures and operation functions (create, connect…). . The implementation details of this header (.c or.m in Objective-C) vary from vendor to vendor, and from system to system.

In unix-like systems, the socket abstraction class’s concrete implementation generally encapsulates some of the underlying connection protocols such as TCP/IP,UDP/IP, etc.

But as the upper program ape we do not have to care about how they are implemented, only need to know, the function of the header file function, you can use this abstraction to achieve the function of network communication.

A socket is an abstract definition. On Linux, we can use netstat -anp to view socket connections. Generally, sockets come in pairs (client and server).

An example:

Socket in reality is the most similar to the phone, phone to make a call, both sides must have a phone (socket port number), telephone line (physical layer connection). A socket connection is like a phone call

Socket long connection (long time communication over the phone)

Have you ever used a socket long connection?

This time there may be a question, socket is not an abstract definition, how can be combined with the long connection?

In general, when referring to socket connections, they refer specifically to the TCP/IP connection protocol, which is a connection-oriented reliable data flow service that can maintain a long, continuous exchange of packets. So we said that the long connection is based on this protocol, and the socket for us to achieve this function, therefore, the connection protocol for a long time, also known as the socket long connection

Socket short connection (a phone call with a specific purpose)

With the long connection is to maintain the connection for a long time to facilitate continuous sending of data, but most of the time we do not need to send for a long time, we just need to confirm that we sent, the server processed, it is ok. Thus, a short connection is created, which is the TCP/IP connection protocol closed on completion.

Our HTTP protocol is based on this

The use of the socket

1. Prepare the socket test tool

sockettest.sourceforge.net/

Usage:

You need to install the Java JDK and click on the JAR package

I’m the splitter ————————————–

The current iOS system is unix-like, so its socket is BSD socket, we will introduce the use of BSD socket

Note: All the code demos that follow are Swift

Preface to this article: Things about Swift Pointers

2. Create a socket

let socketFD = Darwin.socket(domain, SOCK_STREAM.0)
Copy the code

Since all socket-related operations are provided by Module:Darwin, we prefixed the Module name to prevent function naming collisions

Domain: indicates the address description

  • AF_INET: indicates IPv4 (for example, 192.0.0.1).
  • AF_INET6: on behalf of IPv6 (example: the ABCD: EF01:2345-6789: the ABCD: EF01:2345:6789)

SOCK_STREAM: indicates the type of connection to be established

  • SOCK_STREAM:

    We use this when we want to transfer files or when we need to do something to ensure that data can be received.

  • SOCK_DGRAM:

    The established data connection (whether the other party receives data packets is not guaranteed) is based on UDP. After the connection is established, the data packets cannot be accurately delivered

0: indicates the protocol type. If you do not know the protocol type, enter 0

This field is not specified (because I am not sure what this parameter means -_-)

The return value:Int32

The return value is an integer Int32, which needs to be recorded. It is the handle to operate the socket.

Here, my understanding of the return value is that it is possible that there is a global linked list of sockets that need to be operated on, and that the index of that socket is returned to us, and that all subsequent operations are based on that index

If -1 is returned, the socket fails to be created. You can obtain the error code from Darwin. Errno

2. Set the socket

The socket is set up with a series of default Settings, such as the default socket operation (read and write) is blocked (need to wait for the completion of the operation, function return value), but as a server we do not want to be blocked, so socket provides the corresponding modification method

The difference between blocking read and write of a socket

// Set non-blocking
// var status = Darwin.fcntl(socketFD, F_SETFL, O_NONBLOCK)

// Set socket reuse
// var resultOn = 1
//status = setsockopt(socketFD,
// SOL_SOCKET,
// SO_REUSEADDR,
// &resultOn,
// socklen_t(MemoryLayout.size(ofValue: resultOn)))
Copy the code

The setsockopt() operation details:

Please refer to baidu encyclopedia: baike.baidu.com/item/setsoc…

3. Socket connection (client)

Before connecting, we need to do an off-site operation, which is to open our socket test tool and enable TCP Server to set port to 9090

// This function converts "127.0.0.1" into the required UInt32 of the socket
func converIPToUInt32(a: Int, b: Int, c: Int, d: Int) -> in_addr {
    return Darwin.in_addr(s_addr: __uint32_t((a << 0) | (b << 8) | (c << 16) | (d << 24)))}var sock4: sockaddr_in = sockaddr_in()

sock4.sin_len = __uint8_t(MemoryLayout.size(ofValue: sock4))
// Converts IP to UInt32
sock4.sin_addr = converIPToUInt32(a: 127, b: 0.c: 0, d: 1)
// Since the memory bytes are the opposite of the network communication bytes, we need to switch the size of the port we connect to is 9090
sock4.sin_port = CFSwapInt16HostToBig(9090)
// Setting sin_family to AF_INET indicates an IPv4 connection
sock4.sin_family = sa_family_t(AF_INET)
// Swift is more complex than OC
let pointer: UnsafePointer<sockaddr> = withUnsafePointer(to: &sock4, {$0.withMemoryRebound(to: sockaddr.self, capacity: 1, {$0})})

var result = Darwin.connect(socketFD, pointer, socklen_t(MemoryLayout.size(ofValue: sock4)))
guardresult ! = -1 else {
    fatalError("Error in connect() function code is \(errno)")}Copy the code

The main function used here is Darwin.connect()

The flow we need in the code is

1). Find the previously obtained socket operation handle

2). Assemble the sockadDR_in structure and assign the value

3). Cast socketadDR_in to sockaddr(because connect requires this type of pointer)

4). Call connect() and pass the parameter

5). Judge connection success according to return value (return value cannot be -1, generally return 0)

We can see that the socket is connected from the test software

4. Send data packets

In step 3, we have completed the connection establishment of the socket. After the operation, we have experienced the three handshakes of TCP, but as the upper caller, we are not aware of this, so I will mention it separately

The next step is to send or receive data

  • To send data

    // Add a space before "hello" to avoid literal garbled characters recognized by SocketTest3
    let data = "Hi, I'm Apache.".data(using: .utf8) ?? Data(a)// We convert data to a rawPointer, a void * pointer in C
    let rawPointer = data.withUnsafeBytes({UnsafeRawPointer($0)})
    // We need to supply the pointer (the start address of the data) and the length of the data to the function
    var resultWrite = Darwin.write(socketFD, rawPointer, data.count)
    
    guardresultWrite ! = -1 else {
        fatalError("Error in write() function code is \(errno)")}Copy the code

    Writing data is still fairly simple, but for Swift, the trouble is where the data goes to the pointer

  • Receive data

    // Initialize the data receive area
    let readData = Data(count: 500)
    // We convert data to rawPointer
    let readRawPointer = readData.withUnsafeBytes({UnsafeMutableRawPointer(mutating: $0)})
    // The last length is the length of the cache
    let resultRead = Darwin.read(socketFD, readRawPointer, readData.count)
    // Prints the return value of the socket
    print("\(String(data: readData, encoding: .utf8) ?? "")")
    Copy the code

    Receiving the data requires us to enter information on the socketTest and click Send, and then we can see the corresponding returned value in the print console

conclusion

In fact, socket is not mysterious, we feel mysterious to socket, just because we have been using the socket advanced usage, some of the socket advanced encapsulation, so that we do not feel the existence of socket, mystery from this.

In real use, objective-C has a library called CocoaAsyncSocket which is a high-level wrapper around sockets;

Here’s the point:

The SwiftAsyncSocket library I rewrote based on CocoaAsyncSocket was rewritten in pure Swift language in over a month, refactoring part of the logic to make the code easier to read, using the same method as CocoaAsyncSocket.

The reason for writing this library is simple: learn Swift and learn sockets.

I hope you can also try my library, if you have any questions, please contact me.

SwiftAsyncSocket Open Source repository address:

Github.com/chouheiwa/S…

If you think it is still good, please send it to star. If you find any deficiencies, please mention “issue” in Github

At the end

In fact, in the network model, socket layer has been a very advanced encapsulation, we use the socket process, has no knowledge of network IP addressing, data loss retransmission and so on.

Every step we take now is a path paved by our predecessors.

If there are any mistakes in the article, please comment and point out

This article was first published in my blog and public account (see the picture below), if you want to reprint to the public account, please contact me to open permission.

Finally, I wish you all a happy And successful New Year