socket的创建和连接
socket编程
socket的概念
Socket(套接字)是计算机网络编程中的一个基本概念,它为应用程序提供了访问底层网络协议的接口,使得进程间能够通过网络进行通信。在更广泛的意义上,Socket 是操作系统提供的一个抽象层,用于简化网络编程并隐藏复杂的网络协议细节。
Socket 是两个进程间通信的端点,每个 Socket 都有唯一的地址,这个地址包括 IP 地址和端口号。IP 地址用于定位网络上的主机,而端口号则用于区分同一台主机上的不同服务。
socket的类型
socket 可以分为几种类型,主要依据它们支持的协议和通信模式:
- 流式 Socket (SOCK_STREAM): 基于 TCP 协议,提供面向连接的服务,保证数据的顺序传输,且不会丢失数据。
- 数据报 Socket (SOCK_DGRAM): 基于 UDP 协议,提供无连接服务,数据报文独立传输,不保证数据的顺序和完整性,但传输效率较高。
- 原始 Socket (SOCK_RAW): 直接访问 IP 层,允许应用程序直接处理 IP 数据包,常用于网络分析或特殊用途的软件。
socket提供的函数
socket()
创建一个新的确定类型的套接字,类型用一个整型数值标识,并为它分配系统资源。bind()
一般用于服务器端,将一个套接字与一个套接字地址结构相关联,比如,一个指定的本地端口和IP地址。listen()
用于服务器端,使一个绑定的TCP套接字进入监听状态。connect()
用于客户端,为一个套接字分配一个自由的本地端口号。 如果是TCP套接字的话,它会试图获得一个新的TCP连接。accept()
用于服务器端。 它接受一个从远端客户端发出的创建一个新的TCP连接的接入请求,创建一个新的套接字,与该连接相应的套接字地址相关联。send()
和recv()
,或者write()
和read()
,或者recvfrom()
和sendto()
,用于往/从远程套接字发送和接受数据。close()
用于系统释放分配给一个套接字的资源。 如果是TCP,连接会被中断。gethostbyname()
和`gethostbyaddr()select()
用于修整有如下情况的套接字列表: 准备读,准备写或者是有错误。poll()
用于检查套接字的状态。 套接字可以被测试,看是否可以写入、读取或是有错误。getsockopt()
用于查询指定的套接字一个特定的套接字选项的当前值。setsockopt()
用于为指定的套接字设定一个特定的套接字选项。
1. socket()
- 作用:创建一个新的 Socket。
- 参数:
int domain
:地址族,如AF_INET
(IPv4)或AF_INET6
(IPv6)。int type
:Socket 类型,如SOCK_STREAM
(面向连接,流式)或SOCK_DGRAM
(无连接,数据报)。int protocol
:协议,通常是0
,表示使用与type
关联的默认协议。
2. bind()
- 作用:将 Socket 与本地地址(IP 地址和端口号)相关联。
- 参数:
int sockfd
:Socket 文件描述符。const struct sockaddr *addr
:指向包含地址信息的sockaddr
结构体的指针。socklen_t addrlen
:sockaddr
结构体的长度。
3. listen()
- 作用:使 Socket 准备接收连接,通常用于服务器端。
- 参数:
int sockfd
:Socket 文件描述符。int backlog
:待处理连接请求的最大队列长度。
4. accept()
- 作用:接受传入的连接请求,并返回一个新的 Socket 文件描述符用于通信。
- 参数:
int sockfd
:监听的 Socket 文件描述符。struct sockaddr *addr
:可选参数,用于存储客户端的地址信息。socklen_t *addrlen
:可选参数,用于存储地址信息的长度。
5. connect()
- 作用:初始化与远程主机的连接,通常用于客户端。
- 参数:
int sockfd
:Socket 文件描述符。const struct sockaddr *addr
:指向包含远程主机地址信息的sockaddr
结构体的指针。socklen_t addrlen
:sockaddr
结构体的长度。
6. send()
- 作用:发送数据到已连接的 Socket。
- 参数:
int sockfd
:Socket 文件描述符。const void *buf
:指向要发送数据的缓冲区的指针。size_t len
:要发送的数据长度。int flags
:发送标志,如MSG_DONTROUTE
。
7. recv()
- 作用:从 Socket 接收数据。
- 参数:
int sockfd
:Socket 文件描述符。void *buf
:接收数据的缓冲区。size_t len
:缓冲区的大小。int flags
:接收标志,如MSG_PEEK
。
8. sendto()
- 作用:向特定地址发送数据,通常用于无连接的 Socket(如 UDP)。
- 参数:与
send()
类似,额外包括目标地址和地址长度。
9. recvfrom()
- 作用:接收数据并返回源地址信息,通常用于无连接的 Socket(如 UDP)。
- 参数:与
recv()
类似,额外包括源地址信息和地址长度。
10. close()
- 作用:关闭 Socket 文件描述符,释放资源。
- 参数:
int sockfd
:要关闭的 Socket 文件描述符。
11. setsockopt()
- 作用:设置 Socket 的选项,如超时、重用地址等。
- 参数:
int sockfd
:Socket 文件描述符。int level
:设置选项的级别,如SOL_SOCKET
或IPPROTO_TCP
。int optname
:选项名称。const void *optval
:指向选项值的指针。socklen_t optlen
:选项值的长度。
12. getsockopt()
- 作用:获取 Socket 的选项。
- 参数:与
setsockopt()
类似。
13. shutdown()
- 作用:关闭 Socket 的读取或写入方向。
- 参数:
int sockfd
:Socket 文件描述符。int how
:关闭的方向,如SHUT_RD
(读取方向)或SHUT_WR
(写入方向)。
注意事项
- 使用 Socket 编程时,应确保正确处理错误情况,检查每个函数的返回值,并适当地处理任何错误代码。
- 对于某些函数,如
send()
和recv()
,如果在非阻塞模式下使用,可能需要处理 EAGAIN 或 EWOULDBLOCK 错误码,这表明操作无法立即完成。 - 在实际编程中,根据具体需求,可能还需要使用到其他函数,例如
select()
或poll()
用于多路复用,或者fork()
和exec()
用于创建子进程处理连接。
TCP socket通信流程
服务器端流程如下:
- 创建服务器的
socket
- 初始化
sever_addr
(服务器地址) - 将
socket
和server_addr
绑定 bind - 开始监听
listen
- 开一个循环保证服务器不会结束,不断的
accept
接入的客户端请求,进行读写操作write
和read
(send()和recv()也行) - 关闭
socket
1 |
|
客户端流程如下:
- 创建客户端
socket
- 初始化
server_addr
- 连接到服务器
connect
- 利用
write
和read
进行读写操作 (send()和recv()也行) - 关闭
socket
1 |
|