Jun 01, 2021 Article blog
This article is written to give you more details about
Linux C Socket Api
UNIX
Environment Advanced Programming describes
Socket
communication as socket network
IPC
(interprocess communication), which can be used for intercomputer communication as well as in-computer communication, pipelines, message queues, semaphurs, shared memory, and so on.
The first thing that comes first is the file descriptor, and a little more understanding of
Linux
philosophy of all files.
A socket is an abstraction of a communication endpoint. A
s with applications that use file descriptors, access sockets require socket descriptors.
The socket descriptor is implemented with a file descriptor in the
UNIX
system.
int socket (int domain, int type, int protocal);
返回值:成功返回文件(套接字)描述符,出错返回-1
The parameter
domain
determines the characteristics of the communication, including the address format.
Each domain has its own format for the address, meaning that the constants for each domain begin with
AF_
meaning address family.
The parameter
type
determines the type of socket and further determines the communication characteristics.
The following diagram shows some types, but you are free to increase support for other types in your implementation.
protocol
parameter is usually 0, which means that the default protocol is selected by given domain and socket type. W
hen multiple protocols are supported for the same domain and socket type, you can use
proticol
parameter to select a specific protocol.
The default protocol for socket type
SOCK_STREAM
in a
A_FINET
communication
SOCK_DGRAM
domain is
UDP
TCP
(Transport Control Protocol
A_FINET
Byte flow (
SOCK_STREAM
) requires a logical link between local sockets and remote sockets before data is exchanged.
Tcp
There are no message boundaries and a byte streaming service is provided.
That's why you've written about unpacking and unpacking
Qt
transfer pictures before.
Call
socket
and call
open
type, and you get a file descriptor for input and output.
Remember
close
close off when you're not using it.
How do I determine a target communication process?
The identity of a process has two parts: the network address of the computer determines which computer on the network it wants to communicate with
The service can determine a specific process on the computer.
When communicating between processes on the same computer, byte order is generally not considered.
TCP/IP
stack uses large-end byte order.
About byte order we can baidu on their own.
Linux
systems are small-end byte order.
The address determines the socket endpoint in a particular communication domain, and the address format is related to the specific communication domain.
In order for addresses in different formats to be passed in to socket functions, addresses are strongly converted into a common address
sockaddr
representations.
Linux
sockaddr_in
is defined as follows;
struct sockaddr_in { sa_family_t sin_family; i n_port_t sin_port; s truct in_addr sin_addr; u nsigned char sin_zero[8]; };
Where the member
sin_zero
is the fill field, it must all be set at 0.
So examples found online are the use
bzero
.
ubuntu
I'm currently using is defined as follows:
/ Structure describing an Internet socket address. / struct sockaddr_in { __SOCKADDR COMMON (sin ); i n_port_t sin_port; / Port number. / struct in_addr sin_addr; / Internet address. /
/* Pad to size of `struct sockaddr'. */
unsigned char sin_zero[sizeof (struct sockaddr) -
__SOCKADDR_COMMON_SIZE -
sizeof (in_port_t) -
sizeof (struct in_addr)];
};
There are a lot of functions about address queries, and here's a list.
Use
bind
function to bind the address to a socket.
int bind(int sockfd, const struct sockaddr * addr, socklen_t len);
返回值:成功返回0,出错返回-1
Parameter
socklen_t
it would be nice to use
sizeof
to calculate.
For some restrictions on the use of addresses:
The port number cannot be less than 1024 unless the process has the appropriate privileges (i.e. superuser). Visible rules always vary from person to person, as do computers
For Internet domains, if you specify an IP address of
ADDR_ANY
the socket endpoint can be bound to all system network interfaces.
Note:
linux
man
command provides a detailed description of the
api
and there are examples that are pretty good.
If you are dealing with a connection-oriented network service
SOCK_STREAM
or
SOCK_SEQPACKET
you need to establish a connection between the process socket (client) that requests the service and the process socket (server) that provides the service before you start exchanging data.
Use
connect
.
int connect(int sockfd, const struct sockaddr *addr, socklen_t len);
返回值:成功返回0,出错返回-1
Well, this argument is so familiar, it's exactly the same as the parameters of the
bind
function
When
client
server
the connection may fail for some reason.
You can use the algorithm of exponential compensation to find out.
server
listen
to declare that a connection request is acceptable:
Int listen(int sockfd, int backlog);
返回值:成功返回0,出错返回-1
The parameter
backlog
provides a hint of the number of connection requests that the process is about to enter.
Its value is determined by the system, but the upper limit is specified by
SOMAXCONN
in
<sys/socket.h>
Once the queue is full, the system rejects the redundant connection request.
Once the server calls
listen
the socket can receive the connection request.
Use the function
accept
to get the connection request and establish the connection.
Int accept(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict len);
返回值:成功返回文件(套接字)描述符,出错返回-1
The file descriptor returned by the function
accept
is a socket descriptor that connects to the client that calls
connect
T
his new socket descriptor has the same socket type and address family as the original socket
sockfd
The original socket
accept
to accept is not associated with this connection, but remains available and accepts other connection requests.
If you don't care about the client identity, you can set
addr
and
len
to
NULL
otherwise
addr
holds the address of the connected client.
If no connection request waits to be processed,
accept
blocks until a request arrives.
server
can use
poll
or
select
to wait for a request to arrive.
Now that the socket endpoint is represented as a file descriptor, you can use
read
and
write
to communicate through the socket as long as the connection is established.
read
and
write
functions I hardly need to know.
Int send(int sockfd, const void *buf, size_t nbytes, int flags);
返回值:成功返回发送的字节数,出错返回-1
Note: If
send
successfully, it does not necessarily mean that the process at the other end of the connection receives data.
What is guaranteed is that the data has been sent correctly to the network.
The logo I've been using is 0
int recv(int sockfd, const void *buf, size_t nbytes, int flags);
返回值:以字节计数的消息长度,若无可用消息或对方已经按序结束则返回0, 出错返回-1
Still has been 0
If you want to locate the sender, you can use
recvfrom
to get the source address of the data sender.
int recv(int sockfd, void *restrict buf, size_t len, int flag,
struct sockaddr *restrict addr,
socklen_t *restrict len);
返回值:以字节计数的消息长度,若无可用消息或对方已经按序结束则返回0, 出错返回-1
recvfrom
is typically used for no-connect sockets because the sender's address can be obtained.
Otherwise,
recvfrom
is equivalent to
recv
Here's a closer look at
Linux C Socket Api
and I hope it's helpful for everyone, and students interested in
Linux
can take a look at the tutorial:
Linux tutorial: https://www.w3cschool.cn/linux/
Linux Microsyscope: https://www.w3cschool.cn/minicourse/play/linuxcourse
Linux should learn this: https://www.w3cschool.cn/linuxprobe/