Socket了解
目录
Socket的流程和函数
Socket套接字
-
windows
- socket
-
linux
- file descriptor -> fd
-
监听socket
- 由服务器端创建
- 绑定(bind)IP address 和 端口port
- 调用了listen监听的
-
easy function list
name description socket create a socket by type bind 将socket绑定到一个IP与端口的二元组上
(通常是sockaddr类型数组)listen 让socket变为监听状态 connect try to build a TCP connect(use in Client usaully) accept 尝试接受一个连接(use in Server) send 通过一个socket发送数据 recv 通过一个socket接收数据 select 判断一组socket上的读写事件/异常事件 gethostbyname 通过域名获取机器地址 close 关闭一个socket,并回收对应的资源
windows : closesocketshutdown 关闭socket收发通道 setsockopt set a option of socket getsockopt get a option of socket
TCP通信流程
- 服务器Server
- 调用soket函数创建socket(listened)
- 调用bind将socket绑定到一个IP与端口的二元组上
- 调用listen开启监听
- 当有客户端请求连接,调用accept接收连接,产生一个new socket(Client)
- 通过新产生的client socket,调用send/recv与客户端交流数据
- 结束通信,调用close关闭监听soket(client’s socket also close)
- 客户端Client
- 调用socket创建Client’s socket
- 调用connect尝试连接服务器
- 连接成功后调用send/recv与服务器交流数据
- 结束通信,调用close关闭socket
跨平台Socket
|
|
-
socket调用失败返回-1(Windows定义)
-
linux没有这个宏,但可以定义一个
1 2 3 4 5
#define INVALID_HANDLE_VALUE (-1) #ifnedf WIN43 #define SOCKET_ERROR (-1) #endif
-
在linux上可以直接使用socket函数
-
而windows上必须先调用 WSAStartup 函数将socket将dll文件加载到进程地址空间 中 程序退出时用 WSACLeanup卸载相关dll文件.
- ⚠️dll文件是进程相关的,每个线程共享此资源,某个线程调用后,所有线程都可以继续使用.
-
关闭socket函数
-
windows上不按标准
1 2 3
#ifdef WIN32 #define closesocket(s) close(s) #endif
-
-
select函数在windows下第一个参数是不使用的,可随意设置
bind函数
|
|
sockaddr
-
是一种通用的socket地址结构, 不同的协议地址长度不同.
-
sockaddr_in 是sockaddr的一个具体实现.用于IPv4,有IP地址和端口
1 2 3 4 5 6 7 8 9 10 11 12 13
/* Structure describing an Internet socket address. */ struct sockaddr_in { __SOCKADDR_COMMON (sin_); //sin_family in_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)]; };
sin_family 地址族(Address Family)
- AF_INET: IPv4地址族,用于Internet协议第4版
- AF_INET6: IPv6地址族,用于Internet协议第6版
- AF_UNIX: UNIX域套接字,用于同一台机器上的进程间通信
- AF_PACKET: 用于 Packet sockets 发送或接收数据包
- AF_NETLINK: 用于内核用户空间通信的套接字
sin_addr.s_addr 指定IP地址
-
用htonl将宏/int类型的IP地址数字转换为IP地址
1 2 3 4 5 6
/* Address to accept any incoming messages. */ #define INADDR_ANY ((in_addr_t) 0x00000000) /* Address to send to all hosts. */ #define INADDR_BROADCAST ((in_addr_t) 0xffffffff) /* Address indicating an error return. */ #define INADDR_NONE ((in_addr_t) 0xffffffff)
- INADDR_ANY宏: 一串0的IP地址,表示 协议层会自动选一个合适的IP地址.
-
用inet_addr将地址字符串转换为IP地址
1
bindaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
-
IP地址的选择
- INADDR_ANY 相当于地址0.0.0.0
- 可以被公网访问,相当于绑定了外网IP
- 局域网中的地址IP
- 可以被局域网内部机器访问
- 127.0.0.1 本地回环地址
- 只能被本机访问
- INADDR_ANY 相当于地址0.0.0.0
sin_port 绑定端口
htonl,htons|ntohl,ntohs
意思是:host byte order to network byte order (long/short)
network byte order to host byte order (long/short)
network byte order:big-endian 大端模式
host byte order: 根据机器决定.intel机器是little-endian 小端序列
1 2 3 4 5 6 7 8 9
#include <arpa/inet.h> uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort);
- 如果port设为0,操作系统会随机为程序分配一个可用的监听端口,Server一般不会绑定0 - port.因为Server要对外开放,必须让客户端知道确切的IP和Port.
⚠️sockaddr_in 的其他空间用sin_zero char数组填满以对齐sockaddr的空间