CFSocket and Berkeley Sockets
- A CFSocket is a communications channel implemented with a BSD socket.
- For most uses of this API, you will need to include three headers:
Also, #include <sys/socket.h>
- CFSocket can be created from scratch with CFSocketCreate(_ : _ : _ : _ : _ : _ : _ 🙂 and CFSocketCreateWithSocketSignature(_ : _ : _ : _ : _ : ) .
- You can create a CFSocket and connect simultaneously to a remote host by calling CFSocketCreateConnectedToSocketSignature(_: _: _: _: _: _ : ).
- To listen to the message, you need to create a run loop source with CFSocketCreate RunLoopSource(_: _: _ : ) and add it to a run loop with CFRunLoopAddSource(_: _: _:).
- You can select the types of activities, such as connection attempts or data arrivals, that cause the source to fire and invoke your CFSocket’s callback function.
- To send data, you store the data in a CFData and call CFSocketSendData(_: _: _: _ : ).
- When you are through with the socket, you must close it by calling CFSocketInvalidate.
- Berkeley sockets are also known as UNIX domain sockets or BSD sockets.
- For inter-process communication on iOS based on Berkeley sockets, following is the requirement:
- A communication channel
- A client-server connection architecture
- Non-blocking communication (i.e. Asynchronous I/O)
- Message framing for data that is sent through the channel
- Support for complex data to be sent through the channel
- Secure encoding and decoding of data on each end of the channel
- Error and invalidation handling
- We can create BSD socket by: dispatch_fd_t fd = socket(AF_UNIX, SOCK_STREAM, 0);
- AF_UNIX creates a UNIX domain socket (BSD) and SOCK_STREAM makes the socket a stream socket (other options could be datagram or raw).
- For our hosts to communicate with each other we need a particular architecture where we can make sure that multiple hosts can connect to each other.
- In order to achieve this, we use a client-server architecture where one host acts as the server by creating the socket on disk and waiting for connections and the other host(s) act as clients by connecting to the server.
- Moreover, The server binds to the socket and listens for connections while the client connects.
For the client to fully connect, the server has to accept the connection.
- Also, We can construct the socket path by appending a unique identifier to the path of the application group container directory that all applications in the group have read/write access to.
- As long as both server and clients agree on the unique identifier. Also, we now have a channel through which they can communicate.
- First, on the server side we would start the connection by doing: const char *socket_path = … dispatch_fd_t fd = socket(AF_UNIX, SOCK_STREAM, 0); struct sockaddr_un addr; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; unlink(socket_path); strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) – 1); bind(fd, (struct sockaddr *)&addr, sizeof(addr)); listen(fd, kLLBSDServerConnectionsBacklog);
- Similarly, on the client side we would connect to the server with: const char *socket_path = … dispatch_fd_t fd = socket(AF_UNIX, SOCK_STREAM, 0); struct sockaddr_un addr; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) – 1); connect(fd, (struct sockaddr *)&addr, sizeof(addr));