Socket编程
[toc]
C/S模式
(Client) (Server)
socket() socket()
| bind()
| listen()
connect()---建立连接-------->accept()<----
read()<-----数据传输---------write() |
close()<------------------->close() |
|-------|
头:
#include <sys/types.h>
#include <sys/scoket.h>
socket()
int socket(int domain, int type, int protocol);
参数
成功返回文件描述符,错误返回-1
domain:
AF_INET
AF_INET6
AF_NUIX/AF_LOCAL
本地通信
AF_NETLINK
内核间通讯,驱动用
AF_PACKET
原始套接字应用
type:
SOCK_STREAM:流式套接字,TCP
SOCK_DGRAM:数据报套接字,UDP
SOCK_RAW:原始套接字
protocol:
一般填0
原始套接字需要填充,区分IP,或ICMP
bind()
int bind(int sockfd, const struct sockaddr *addr, socklen_taddrlen);
参数
sockfd:通过socket函数拿到的fd
addr:struct sockaddr的结构体变量的地址
//通用结构体
struct sockaddr{
sa_family_t sa_family; //2字节
char sa_data[14]; //14字节
}
struct sockaddr_in{
sa_family_t sin_family; //2字节
in_port_t sin_port; //2字节
struct in_addr sin_addr; //4字节
sin_zero[8];
}
struct in_addr{
unit32_t s_addr; //32位网络字节序的IP,4字节
}
sockaddr_in结构体重包含一个sin_zero[8]的填充位,此填位必须清零
addrlen:地址的长度
如果是IPV6编程,要使用struct scokaddr_in6结构体(man 7 IPV6),通常更通用的方法是通过sturct sockaddr_storage来编程
listen()
int listen(int sockfd, int backlog);
参数
成功返回0,失败返回-1
sockfd:绑定后的fd
backlog:一般填5
同时允许几路客户端和服务器进行正在链接的过程(正在三次握手)
一般填5,ARM平台,最大8
内核中服务器的嵌套字fd会维护2个链表:
1,正在三次握手的客户端链表(数量 = 2×backlog+1)
2,已经建好客户端链接的链表(已经完成3次握手分配好了newfd)
accept()
阻塞等待客户端链接请球
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数
成功返回已经链接的新的newfd,失败返回-1
sockfd:经过绑定与listen的fd
addr
connect()
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数
成功返回0,出错返回-1
send()
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
参数
比write函数多一个flags参数
flags:
一般填0,和write一样
MSG_DONTWAIT
不阻塞
MSG_OOB
用于发送TCP类型的带外数据(out-of-band)
recv()
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
参数
比read汗说多一个flags参数
flags:
一般填0,和read函数相同
MSG_DONTWAIT
不阻塞
MSG_OOB
用于读取TCP类型的带外数据(out-of-band)
MSG_PEEK
读取数据时,并不读走数据,保留字符流中的数据