文章目录
套接字概念
socket套接字是进程之间一种通信机制,通过套接字可以在不同进程之间进行数据交流。在TCP/UDP中,"IP+TCP或UDP端口号"可以唯一标识网络通讯中的一个进程,"IP地址+端口号"就是一个socket套接字。
端口号
端口号是一个2字节的16位整数,用来标识一个进程,它告诉操作系统 当前这个数据要交给哪个进程来处理。一个端口号只能被一个进程占用,但是一个进程可以有多个端口号。
网络字节序
TCP/IP协议规定,网络数据流采用大端字节序(高位字节数据存放在内存低地址数,低位字节数据存放在内存高地址数)。不管这台主机是大端机还是小端机都是按照大端字节序来接收数据,不过小端机需要转换一下。
套接字类型
流套接字
流套接字提供了一个可靠的、面向连接的通信机制,可以顺序地传输数据。在TCP/IP协议中,TCP协议采用的就是流套接字。
数据报套接字
数据报套接字提供了一种无连接、不可靠的通信机制,数据以独立的数据包形式传输。在TCP/IP协议中,UDP协议采用的就是数据报套接字。
socket常见API
socket API是一层抽象的网络编程接口,适用于各种底层网络协议。
socket函数
// 创建socket文件描述符(TCP/UDP。客户端+服务器)
int socket(int domain,int type, int protocol);
domain:
AF_INET 这是大多数用来产生socket的协议,使用TCP或UDP来传输,用IPv4的地址
AF_INET6 与上面类似,不过是来用IPv6的地址
AF_UNIX 本地协议,使用在Unix和Linux系统上,一般都是当客户端和服务器在同一台及其上的时候使用
type:
SOCK_STREAM 这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。
SOCK_DGRAM 这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的连接。
SOCK_SEQPACKET该协议是双线路的、可靠的连接,发送固定长度的数据包进行传输。必须把这个包完整的接受才能进行读取。
SOCK_RAW socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)
SOCK_RDM 这个类型是很少使用的,在大部分的操作系统上没有实现,它是提供给数据链路层使用,不保证数据包的顺序
protocol:
传0 表示使用默认协议。
返回值:
成功:返回指向新创建的socket的文件描述符,失败:返回-1,设置errno
bind函数
// 绑定端口号(TCP/UDP,服务器)
int bind(int sockfd const struct sockaddr *address, socklen_t address_len);
sockfd:
socket文件描述符
address:
构造出IP地址加端口号
addrlen:
sizeof(address)长度
返回值:
成功返回0,失败返回-1, 设置errno
服务器程序所监听的网络地址和端口号通常是固定不变的,客户端程序得知服务器程序的地址和端口号后就可以向服务器发起连接,因此服务器需要调用bind绑定一个固定的网络地址和端口号。
bind()的作用是将参数sockfd和addr绑定在一起,使sockfd这个用于网络通讯的文件描述符 监听addr所描述的地址和端口号。struct sockaddr *是一个通用指针类型,addr参数实际上可以接受多种协议的sockaddr结构体,而它们的长度各不相同,所以需要第三个参数addrlen指定结构体的长度。
listen函数
// 开始监听socket(TCP,服务器)
int listen(int sockfd, int backlog);
sockfd:
socket文件描述符
backlog:
挂起的连接队列的最大长度
返回值:
成功返回0,失败返回-1
accept函数
// 接收请求(TCP,服务器)
int accept(int sockfd, struct sockaddr* address, socklen_t* address_len);
sockdf:
socket文件描述符
address:
传出参数,返回链接客户端地址信息,含IP地址和端口号
addrlen:
sizeof(address)长度
返回值:
成功返回一个新的socket文件描述符,用于和客户端通信,失败返回-1,设置errno
当socket模式设置为阻塞,accept函数的功能是阻塞等待client发起三次握手,当3次握手完成的时候,accept解除阻塞,并从全连接队列中取出一个socket,就可以对这个socket连接进行读写操作
connect函数
// 建立连接(TCP,客户端)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockdf:
socket文件描述符
addr:
传入参数,指定服务器端地址信息,含IP地址和端口号
addrlen:
传入参数,传入sizeof(addr)大小
返回值:
成功返回0,失败返回-1,设置errno
调用connect函数将激发TCP的三次握手过程,而且仅在连接建立成功或出错时才返回
sockaddr结构
sockaddr在头文件#include <sys/socket.h>中定义,sockaddr的缺陷是:sa_data把目标地址和端口信息混在一起了。sockaddr_in在头文件#include<netinet/in.h>或#include <arpa/inet.h>中定义,该结构体解决了sockaddr的缺陷,把p目标地址和端口号分开储存在两个变量中。
sockaddr结构
c
struct sockaddr
{
__SOCKADDR_COMMON (sa_);
char sa_data[14];
};
sockaddr_in结构
c
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};
struct sockaddr_in
{
__SOCKADDR_COMMON (sin_);
in_port_t sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[sizeof(struct sockaddr) -
__SOCKADDR_COMMON_SIZE -
sizeof(in_port_t) -
sizeof(struct in_addr)];
};