socket八股
1. socket()
函数简介#
socket()
函数是创建一个套接字(socket)以进行网络通信的系统调用。套接字可以用于 TCP(面向连接)或 UDP(无连接)的通信。调用 socket()
函数时,需要指定协议族、套接字类型和协议。
socket()
函数原型:#
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
-
domain
:指定通信协议族(地址族),常见的值有:- AF_INET:IPv4 网络协议。
- AF_INET6:IPv6 网络协议。
- AF_UNIX:本地通信(Unix域套接字)。
-
type
:指定套接字类型,常见的值有:- SOCK_STREAM:字节流(面向连接,TCP)。
- SOCK_DGRAM:数据报(无连接,UDP)。
- SOCK_RAW:原始套接字,允许访问底层协议。
-
protocol
:指定使用的协议,一般为0
,让系统自动选择合适的协议。- 对于 SOCK_STREAM,协议是 TCP。
- 对于 SOCK_DGRAM,协议是 UDP。
示例:#
int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建一个 TCP 套接字
2. 阻塞和非阻塞模式#
阻塞模式:#
默认情况下,套接字是以阻塞模式运行的。这意味着,当调用例如 recv()
或 send()
等阻塞系统调用时,程序会等待数据的接收或发送操作完成后才返回。例如,当一个套接字在等待数据时,调用 recv()
函数会一直阻塞,直到接收到数据或发生错误。
非阻塞模式:#
在非阻塞模式下,系统调用会立即返回,而不会等待操作完成。这样,程序可以在不阻塞的情况下执行其他任务,而不是等待某些操作完成。
使用 fcntl()
设置非阻塞模式:#
可以使用 fcntl()
函数将套接字设置为非阻塞模式:
#include <fcntl.h>
#include <unistd.h>
// 将套接字设置为非阻塞模式
void set_nonblocking(int sockfd) {
int flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
}
当套接字是非阻塞时,像 recv()
、send()
这样的系统调用会立即返回:
- 如果没有数据可读,
recv()
会返回-1
,并将errno
设置为EAGAIN
或EWOULDBLOCK
。 - 如果无法发送数据,
send()
也会返回-1
,并将errno
设置为EAGAIN
。
3. Socket 通信的流程#
下面是一个标准的 TCP 套接字通信流程,分为 服务器端 和 客户端。
服务器端的流程:#
- 创建套接字:使用
socket()
函数创建一个套接字。 - 绑定套接字:使用
bind()
函数将套接字绑定到一个本地地址和端口。 - 监听连接:使用
listen()
函数监听客户端连接请求。 - 接受连接:使用
accept()
函数接受客户端的连接。 - 收发数据:使用
recv()
和send()
函数接收和发送数据。 - 关闭连接:使用
close()
函数关闭套接字。
客户端的流程:#
- 创建套接字:使用
socket()
函数创建一个套接字。 - 连接服务器:使用
connect()
函数连接到服务器。 - 收发数据:使用
recv()
和send()
函数接收和发送数据。 - 关闭连接:使用
close()
函数关闭套接字。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理