(1)socket套接字
1)在linux环境下,socket用于表示进程间网络通信的特殊文件类型,其本质是内核借助缓冲区形成的伪文件(不占磁盘空间,除此之外还有二进制文件,管道,字符文件)。
2)伪文件也可以像文件一样的操作(读写),区别在于管道用于本地进程间的通信,套接字多用于网络进程间数据的传递。
3)在TCP/IP协议中,IP地址可以在网络环境中唯一标识一个主机,端口号则在主机中唯一标识一个进程。因此在网络中,IP地址+端口号就对应一个socket。
4)在网络通信中,套接字一定成对存在。一段的发送缓冲区对应对端的接收缓冲区,使用同一个文件描述符可以操作发送缓冲区和接收缓存区。(全双工,文件描述符一个,数据缓存区两个)
(2)网络字节序
1)大端字节序:低地址高位、高地址低位
小端字节序:低地址低位,高地址高位(windows)
2)网络数据流地址规定:先发出的数据是低地址,后发出的数据是高地址。
TCP/IP协议规定,网络数据流采用大端字节序,即低地址高字节。
3)为了保证网络程序具有可移植性,需要调用库函数做网络字节序和主机字节序的转换。
#include<arpa/inet.h>
uint32_t htonl(uint32_t hostlong); //host to net long IP
uint16_t htons(uint16_t hostshort); //host to net short port
uint32_t ntohl(uint32_t netlong); //net to host long IP
uint16_t ntohl(uint16_t netshort); //net to host short port
如果主机是小端字节序,这些函数将参数做相应的大小端转换后返回。如果主机是大端字节序,则不做转换。
(3)IP地址转换
1)通常我们所说的IP地址(如192.168.1.200),属于点分十进制形式,而我们在网络传输中通常使用到的是网络字节序形式,因此在传输的过程中,首先需要把点分十进制形式的字符串转换为网络字节序格式。
2)IP地址转换函数
#include<arpa/inet.h>
int inet_pton(int af ,const char *src, void *dst);//点分十进制字符串转换为网路字节序
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);//网络字节序转换为点分十进制
参数:af(IP地址格式):AF_INET(IPV4) AF_INET6(IPV6)
3)sockaddr数据结构
struct sockaddr诞生于IPV4协议时代,函数的接口通常使用(struct sockaddr),但是现在为了兼容IPV6,将struct sockaddr 改变成了struct sockaddr_t格式(因此现在定义变量时使用struct sockaddr_t,在传参数时使用struct sockaddr(不能直接用这个定义变量))
struct sockaddr{ struct sockaddr_in{ struct in_addr{
sa_family_t sa_family; _kernel_sa_family_t sin_family; //地址结构类型 _be32 s_addr;IP地址
char sa_data[14]; _be16 sin_port; //端口号 };
}; struct in_addr sin_addr;
......
};
(4)Socket模型创建流程图
注:TCP客户端没有调用bind()函数绑定IP和端口号,系统会自动给它分配IP和端口号,但在TCP服务端则不能省去bind()函数。
(5)网络套接字函数
头文件:#include<sys/types.h>
#include<sys/socket.h>
1)打开一个网络通讯端口:socket函数(服务端、客户端)
int socket(int domain, int type ,int protocol);
参数:domain:协议类型,AF_INET(IPV4) AF_INET6(IPV6) AF_UNIX(本地协议)
type:SOCK_STREAM(流失协议,默认为TCP传输) SOCK_DGRAM(报式协议,默认使用UDP传输)
protocol:使用默认协议
返回值:成功返回新创建socket的文件描述符,失败返回-1.
2)绑定IP和端口号:bind函数(服务端/客户端)
int bind(int sockfd , const struct sockaddr *addr, socklen_t addrlen);
参数:sockfd : socket 文件描述符
addr:绑定了IP和端口号的结构体
addrlen:sizeof(addr)长度
返回值:成功返回0,失败返回-1.
3)指定监听上限数(同一时间允许多少客户端和服务器连接):listen函数(服务端)
int listen(int sockfd, int backlog)
参数:backlog:排队进行三次握手队列和刚刚建立三次握手队列的链接数和。
返回值:成功返回0,失败返回-1
4)接收连接请求:accept函数(服务端调用)
int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);
参数:addr(传出参数)返回链接客户端地址信息,含IP和端口号。
5)连接客户端:connect函数(客户端调用)
int connect(int sockfd,const struct *sockaddr,socklen_t addrlen)
参数:addr:传入参数,指定服务器的地址信息,含IP地址和端口号。
addrlen:sizeof(addr)大小
返回值:成功返回0,失败返回-1.
addrlen(传入传出参数):传入sizeof(addr)大小,函数返回真正接收到的地址结构体的大小。
返回值:生成一个新的socket文件描述符,用于和客户端通信,失败返回-1
(6) C/S模型之TCP:实现最简单的客户端、服务器程序
服务器端:可通过命令nc +自己ip +端口号完成自我通信(在不同进程使用)nc 182.168.1.100 6666
客户端: