常用函数
socket() | 创建套接字 |
bind() | 绑定本机地址和端口 |
connect() | 建立连接 |
listen() | 设置监听套接字 |
accept() | 接收连接 |
recv(), read(), recvfrom() | 数据接收 |
send(), write(), sendto() | 数据发送 |
close(), shutdown() | 关闭套接字 |
int socket(int domain, int type, int protocol);
/*********************************************************************************
* 描述:创建套接字通信
* 参数:
domain:协议族
AF_INET IPv4 Internet protocols
AF_UNIX Local communication
type:类型
SOCK_STREAM:tcp
SOCK_DGRAM:udp
protocol:总是0
* 返回值:成功返回套接字描述符 失败返回 -1
* 头文件:
#include <sys/types.h>
#include <sys/socket.h>
**********************************************************************************/
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/*********************************************************************************
* 描述:绑定本机ip和端口
* 参数:
sockfd:套接字描述符
addr:地址信息(ip地址+端口+协议)
struct sockaddr_un // 用于本地间通信
struct sockaddr_in // 用于网络通信
{
u_short sin_family; // 地址族, AF_INET,2 bytes
u_short sin_port; // 端口,2 bytes
struct in_addr sin_addr; // IPV4地址,4 bytes
char sin_zero[8]; // 8 bytes unused,作为填充
};
addrlen:长度
* 返回值:成功返回 0,失败返回 -1
* 头文件:
#include <sys/types.h>
#include <sys/socket.h>
**********************************************************************************/
地址结构一般用法
// 1、定义一个struct sockaddr_in类型的变量并清空
struct sockaddr_in my_addr;
memset(&my_addr, 0, sizeof(my_addr));
// 2、填充地址信息
my_addr.sin_family = PF_INET;
my_addr.sin_port = htons(8888);
my_addr.sin_addr.s_addr = inet_addr("192.168.1.100");
// 3、将该变量强制转换为struct sockaddr类型在函数中使用
bind(sockfd, (struct sockaddr*)(&my_addr), sizeof(my_addr));
listen()和accept()是TCP服务器端使用的函数
int listen(int sockfd, int backlog);
/*********************************************************************************
* 描述:进入监听模式(设置监听套接字)
* 参数:
sockfd:套接字描述符
backlog:队列长度,同时允许几路客户端和服务器进行正在连接的过程(正在三次握手)一般填5。测试得知,ARM最大为8
* 返回值:成功返回 0,失败返回 -1
* 头文件:
#include <sys/types.h>
#include <sys/socket.h>
**********************************************************************************/
内核中服务器的套接字fd会维护2个链表:
1、正在三次握手的的客户端链表(数量=2*backlog+1) 2、已经建立好连接的客户端链表(已经完成3次握手分配好了newfd)
比如:listen(fd, 5); // 表示系统允许11 (=2*5+1) 个客户端同时进行三次握手
|
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
/*********************************************************************************
* 描述:阻塞等待客户端建立链接
* 参数:
sockfd:套接字描述符
addr:作为输出参数,用于获取对方的地址信息。可以置NULL
addrlen:作为输出参数,用户获取对方的地址长度。可以置NULL
* 返回值:成功返回(建立好的连接套接字,通信套接字) 失败返回 -1
* 头文件:
#include <sys/types.h>
#include <sys/socket.h>
**********************************************************************************/
connect()是客户端使用的函数
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/*********************************************************************************
* 描述:连接服务器
* 参数:
sockfd:套接字描述符
addr:服务器地址信息
addrlen:地址长度
* 返回值:成功返 0,失败返回 -1
* 头文件:
#include <sys/types.h>
#include <sys/socket.h>
**********************************************************************************/
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
/*********************************************************************************
* 描述:发送,可以用write函数代替
* 参数:
sockfd:套接字描述符
buf:要发送数据
len:发送字节数
flags:方式(0:阻塞)
* 返回值:成功返回发送字节数,失败返回 -1
* 头文件:
#include <sys/types.h>
#include <sys/socket.h>
**********************************************************************************/
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
/*********************************************************************************
* 描述:接收,可以用read函数代替
* 参数:
sockfd:套接字描述符
buf:保存接受的数据
len:buf大小
flags:方式(0:阻塞)
* 返回值:成功返回接收字节数,-1:失败, 0:关闭(对方下线了)
* 头文件:
#include <sys/types.h>
#include <sys/socket.h>
**********************************************************************************/
read(),write()
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
/*********************************************************************************
read()和write()经常会代替recv()和send()。
使用read()/write()和recv()/send()时最好统一。
**********************************************************************************/
sendto(),recvfrom()
ssize_t sendto(int socket, void *message, size_t length, int flags, struct sockaddr *dest_addr, socklen_t dest_len);
ssize_t recvfrom(int socket, void *buffer, size_t length, int flags, struct sockaddr *address, socklen_t *address_len);
/*********************************************************************************
这两个函数一般在使用UDP协议时使用。
**********************************************************************************/
close(),shutdown()
int close(int sockfd); // 关闭双向通讯
int shutdown(int sockfd, int howto);
/*********************************************************************************
TCP连接是双向的(是可读写的)。
当我们使用close时,会把读写通道都关闭,有时侯我们希望只关闭一个方向,这个时候我们可以使用shutdown。
针对不同的howto,系统会采取不同的关闭方式。
howto = 0 关闭读通道,但是可以继续往套接字写数据。
howto = 1 和上面相反,关闭写通道。只能从套接字读取数据。
howto = 2 关闭读写通道,和close()一样。
**********************************************************************************/
其他函数
in_addr_t inet_addr(const char *cp);
// 功能:将点分十进制的IP转换成网络字节序
// 头文件:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/**********************************************************************************/
char *inet_ntoa(struct in_addr in);
// 功能:将网络字节序ip转换成本机网络地址(字符串形式)
/**********************************************************************************/
uint16_t htons(uint16_t hostshort);
// 功能:将主机字节序转换网络字节序
// 头文件:
#include <arpa/inet.h>
/**********************************************************************************/
uint16_t ntohs(uint16_t netshort);
// 功能:将网络字节序转换成主机字节序