一、socket
函数作用:建立一个新的socket套接字
函数原型:
int socket(int domain,int type, int protocol)
函数参数:1)domain:表示使用何种地址协议类型。
AF_INET:IPV4,AF_INET6:IPV6
2)type:SOCK_STREAM TCP面向数据流
SOCK_DGRAM UDP协议
SOCK_RAM 提供原始网络协议
3)protocol:指定socket传输协议编号,设为0即可
返回值:成功返回socket套接字描述符,失败返回-1
头文件:#include <sys/socket.h>
二、bind
函数作用:绑定IP地址
函数原型:
int bind(int sockfd,struct sockaddr* my_addr,socklen_t addrlen)
函数参数:1)sockfd:套接字描述符
2)my_addr:主机地址
3)addlen:sockaddr的地址长度,是my_addr结构的长度,可以设置成sizeof(struct sockaddr)
struct sockaddr_in
{
sa_family_t sin_family;//地址族:AF_UNIX,AF_INET,AF_INET6
uint16_t sin_port;//端口号,要用网络字节表示
struct in_addr sin_addr;//ipv4地址结构体
};
struct sockaddr
{
sa_family_t sin_family//地址族:AF_UNIX,AF_INET,AF_INET6
char sa_data[15];//地址值
};
//IPV4地址结构体
struct in_addr
{
u_int32_t s_addr;//IPV4地址,要用网络字节表示
};
// struct sockaddr是通用的套接字地址,
// 而struct sockaddr_in则是internet环境下套接字的地址形式,
// 二者长度一样,都是16个字节。
// 二者是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr。
// 一般情况下,需要把sockaddr_in结构强制转换成sockaddr结构再传入系统调用函数中。
// 只需要记住,填值的时候使用sockaddr_in结构,
// 而作为函数的参数传入的时候转换成sockaddr结构就行了,毕竟都是16个字符长。
头文件:#include<sys/type.h>
#include<sys/socket.h>
返回值:成功返回0,失败返回-1
三、listen
函数作用:聆听网络,等待连接
函数原型:
int listen(int sockfd,int backlog)
函数参数: 1)sockfd:套接字描述符
2)backlog:允许接入的客户端数目
注意:listen并没有连接,只是设置socket的listen模式而已,真正的连接是accept
返回值:成功0,失败-1
四、accept
函数作用:接收网络的连接,客户端连接,三次握手
函数原型:
int accept(int sockfd,struct sockaddr* addr,socklen_t* addlen)
函数参数:1)addr:连接成功填充远端客户机的地址
2)addelen:struct sockaddr的长度
返回值:成功返回新的fd,出错返回-1
函数accept所返回的文件描述符是套接字描述符,该描述符连接到调用connect的客户端。这个新的套接字描述符和原始套接字(sockfd)具有相同的套接字类型和地址族。传给accept的原始套接字没有关联到这个连接,而是继续保持可用状态并接收其他连接请求。
五、connect
函数作用:建立socket连接,客户端连接服务器使用
函数原型:
int connect(int sockfd,struct sockaddr* serv_addr,int addrlen)
函数参数:1)serv_addr:表示要连接的服务器IP地址
2)addrlen:struct sockaddr的长度
返回值:成功0,出错-1
六、send
函数作用:经过socket传送数据,向对方发送数据
函数原型:
int send(int sock_fd,const void* msg,int len,unsigned int flags)
函数参数:1)sock_fd:accept建立起来的socket连接远方的IP地址的套接字描述符
2)msg:发送的数据
3)len:数据长度
4)flags:设为0
返回值:成功是实际传递出去的字节数,出错-1
七、recv
函数作用:经过socket接收数据
函数原型:
int recv(int socket_fd,void* buf,int len,unsigned int flag)
函数参数:1)sock_fd:accept以后的socket套接字描述符
2)buf:存放数据地址
3)len:接收数据的最大长度
返回值:成功返回接收的字节数,出错-1
八、字节序的转化函数
头文件 #include<apra/inet.h>
uint32_t htonl(uint32_t hostin32) 32位数据传送,从主机到网络
uint16_t htons(uint16_t hostin16) 16位数据传送,从主机到网络
uint32_t ntohl(uint32_t netint32) 32位的数据接收,从网络到主机
uint16_t ntohs(uint16_t netint16) 16位的数据接收,从网络到主机
九、地址格式的转换
头文件 #include <arpa/inet.h>
inet_port()
函数原型:
int inet_pton(int domain,const char* restrict str,void* restrict addr)
函数参数:1) domain:internet地址族,AF_INET,AF_INET6
2) str:地址字符串(点分十进制)指针
3) addr:internet地址,32位IPV4地址(网络字节序)
返回值:成功1,格式无效0,出错-1
函数作用:点分十进制转化位网络字节序
inet_ntop()
函数原型:
inet_ntop(int domain,const void* restrict addr,char* restrict str,socklen_t size)
函数参数:1) domain:internet地址族,AF_INET,AF_INET6
2) addr:internet地址,32位IPV4地址(网络字节序)
3) str:地址字符串(点分十进制)指针
4) size:地址字符串大小
返回值:成功返回地址字符串指针,出错返回NULL
函数作用:网络字节序转化成点分十进制
十、字节操作函数
#include <string.h>
void bzero(void* dest,size_t nbytes)
void bcopy(const void* src,void* dest,size_t nbytes)
int bcmp(const void* ptr1,const void* ptr2,size_t nbytes)
返回值:0 相等,非0 不相等
#include<string.h>
void* memset(void* dest,int c,size_t len);
void* memcpy(void* dest,void* src,size_t nbytes)
int memcmp(const void* ptr1,const void* ptr2,size_t nbytes)
返回值:0 相同,>0或<0 不相同,进行比较操作时,假定两个不相同的字节均为无符号字符(unsigned char)
十一、close
#include<unistd.h>
int close(int sockfd)
返回:0 ok,-1 出错
十二、read/write
头文件:#include <unistd.h>
函数原型:
ssize_t read(int fd,void* buf,size_t nbytes)
返回值:返回读到的字节数;若已到文件尾返回0;若出错返回-1
函数原型:
ssize_t write(int fd,void* buf,size_t nbytes)
返回值:若成功返回已写的字节数;若出错返回-1
十三、地址信息函数getsockname/getpeername
getsockname
头文件:#include <sys/socket.h>
函数原型:
int getsockname (int sockfd, struct sockaddr* address, socklen_t address_len)
函数返回值:成功返回0;失败返回-1
函数作用:getsockname获取sockfd对应的本端socket地址,并将其存储于address参数指定的内存中,该socket地址长度则存储于address_len参数指向的变量中
getpeername
头文件:#include <sys/socket.h>
函数原型:
int getpeername (int sockfd, struct sockaddr* address, socklen_t address_len)
函数返回值:成功返回0;失败返回-1
函数作用:getpeername获取sockfd对应远端的socket地址,参数同getsockname
十四、Linux网络编程之端口复用
我们知道,TCP连接在进行4次挥手断开连接时,为了确保最后一次ACK到达对端,保证对端正确关闭资源,以防止对傻傻等待浪费网络和计算机资源,要求等待2MSL时常,那么对于我们需要立即重启程序的情况不友好,有过经验的朋友都知道,我们关闭一个链接,然后立马重启这个连接,一般会报bind失败:
bind error: Address already in use
表示端口号正在被占用,因为前一次的链接还没有被完全释放,通过指令可以查看到上次连接处于TIME_WAIT状态:
假设上次使用的端口号是6000
netstat -apn | grep 6000
如何设置断口复用:允许等待2MSL的同时,继续使用该端口进行监听
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int setsockopt(int sockfd, int level, int optname,
const void *optval, socklen_t optlen);
需要将socket描述符选项设置SO_REUSEADDR设置为1:
代码加入到bind()调用之前即可:
int opt = 1;
setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));