apue读书笔记之socket
来源:互联网 发布:北京unity3d培训 编辑:程序博客网 时间:2024/05/19 03:28
创建 Socket:
#include<sys/socket.h>
intsocket(int domain, int type, int protocol);
domain: AF_INET AF_UNIX(AF_LOCAL 在某些系统)规定通信的本质,比如地址的格式
type: SOCK_STREAM SOCK_DGRAM SOCK_RAW SOCK_SEQPACKET 规定数据的传输方式
protocol: 通常为0,使用默认值。
四种 type 区别:
感觉听上去很简单,其实还是需要理解的
- SOCK_DGRAM: 数据报方式。无连接,发出去的数据不保证能收到,但是收到的字节数和发出去的肯定相等。
- SOCK_STREAM: 面向连接的流。注意是流,所以一次收到的字节数和一次发出的字节数不一定相等。有可能一次发出的数据,要分几次收到;有可能几次发出的数据,一次都能收到。但是肯定是面向连接的。消息之间没有界限。
- SOCK_SEQPACKET: 面向连接的基于消息的传输。消息之间是有界限的。协议: SCTP
- SOCK_RAW: 数据报接口,面向IP层,需要自己添加协议头什么的。需要权限
Socket 常用的普通IO函数:
close fcntl ioctl select poll dup/dup2 read/readvwrite/writev
关闭 Socket:
close 直接关闭
shutdown 可以关闭socket某个方向的传输
#include <sys/socket.h>
int shutdown (int sockfd, int how);
Returns: 0 if OK, 1 on error
how: SHUT_RD/SHUT_WR/SHUT_RDWR
为什么需要shutdown?
- close 需要等待所有引用的描述符都关闭才最终关闭,shutdown不会
- shutdown可以关闭指定方向的传输
设置socket选项
#include<sys/socket.h>
intsetsockopt(int sockfd, int level, int option, const void *val,socklen_t len);
Returns: 0 if OK, 1 on error
intgetsockopt(int sockfd, int level, int option, void *restrict val, socklen_t*restrict lenp);
常用的选项:
SO_REUSEADDR 防止服务器突然重启时重新绑定失败。
地址格式
structsockaddr {
sa_family_t sa_family; /* address family */
char sa_data[]; /* variable-length address */
.
.
.
};
这个是POSIX规定的格式,系统调用用的都是这个接口,所以需要强制转换。不同的平台会有不同的实现方式。
AF_INET地址格式:
#include<netinet/in.h>
structin_addr {
in_addr_t s_addr; /* IPv4 address */
};
structsockaddr_in {
sa_family_t sin_family; /* address family */
in_port_t sin_port; /* port number */
struct in_addr sin_addr; /* IPv4 address */
};
上面是 Single UNIXSpecification 规定的标准,每个平台有自己的实现。Linux平台的实现如下:
structsockaddr_in {
sa_family_t sin_family; /* address family */
in_port_t sin_port; /* port number */
struct in_addr sin_addr; /* IPv4 address */
unsigned char sin_zero[8]; /* filler */
};
其中 sin_zero 必须全部设为0.
地址和可读字符串之间的转换:
#include<arpa/inet.h>
constchar *inet_ntop(int domain, const void *restrict addr, char *restrict str,socklen_t size);
Returns: pointer to address string on success, NULL onerror
intinet_pton(int domain, const char *restrict str, void *restrict addr);
Returns: 1 on success, 0 if the format is invalid, or -1on error
size 表示能容纳输出字符的数组大小(INET_ADDRSTRLEN 或者 INET6_ADDRSTRLEN)
domain 只能是 AF_INET 或者AF_INET6
地址查找:
最常用的函数:
#include<sys/socket.h>
#include<netdb.h>
intgetaddrinfo(const char *restrict host, const char *restrict service, conststruct addrinfo *restrict hint, struct addrinfo **restrict res);
Returns: 0 if OK, nonzero error code on error
voidfreeaddrinfo(struct addrinfo *ai);
返回错误的时候错误信息由下面的函数取得:
#include<netdb.h>
constchar *gai_strerror(int error);
error 是 函数的返回值
getnameinfo 通过地址来查找主机名和服务名:
#include<sys/socket.h>
#include<netdb.h>
intgetnameinfo(const struct sockaddr *restrict addr, socklen_t alen, char*restrict host, socklen_t hostlen, char *restrict service, socklen_t servlen,unsigned int flags);
Returns: 0 if OK, nonzero on error
注意:
host 指向 主机名称或者 ip地址
service 指向服务名称或者端口号 (/etc/drivers 里面有服务名称到端口号的映射)
填充 hint 会缩小查询结构的范围
注意 flag 参数的选取。
绑定地址
系统调用:
#include<sys/socket.h>
intbind(int sockfd, const struct sockaddr *addr, socklen_t len);
Returns: 0 if OK
注: addr 参数一般是有 sockaddr_in 强制转换来的, len参数一般是sizeof 来获取的。
在AF_INET 中,地址被指定 INADDR_ANY 将绑定本机所有的IP地址的对应端口。
获取socket绑定的地址:
#include<sys/unistd.h>
intgetsockname (int sockfd, struct sockaddr *localaddr, int *addrlen);
获取本机
intgetpeername(int sockfd, struct sockaddr *peeraddr, int *addrlen);
获取对方
注意: getpeername 只能在面向连接的连接中使用。在UDP中调用recvfrom函数会返回对方的地址。
建立连接:
#include<sys/socket.h>
intconnect(int sockfd, const struct sockaddr *addr, socklen_t len);
Returns: 0 if OK
注:
在非阻塞模式中,如果不能马上建立连接,将返回1,errno设置为EINPROGRESS.程序可以使用select或者poll来确定socket什么时候是可写的。
connect可以用在UDP中,这样以后发数据的时候就不用每次都指定发送地址。
监听:
#include<sys/socket.h>
intlisten(int sockfd, int backlog);
Returns: 0 if OK, 1 on error
backlog 指定最大允许接入的连接数量。
接入连接:
#include<sys/socket.h>
intaccept(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict len);
Returns: file (socket) descriptor if OK, 1 on error
返回接入的socket 描述符。addr 返回接入的地址和端口号,注意接入的客户地址中的端口号是对方主机随即分配的哦。
数据传输
发送: write / send/ sendto / sendmsg
接收: read / recv/ recvfrom / recvmsg
注意:
sendto recvfrom 一般用在 UDP中
一些常用的flags:MSG_OOB MSG_PEEK MSG_NOBLOCK
带外数据(Out of band data)
TCP支持,紧急数据,高优先级发送。
带外数据只支持一个字节,发送的时候指定 MSG_OOB
接收到数据的时候,产生SIGURG 信号,但是必须先进行设置才能接收到信号:
- fcntl(sockfd, F_SETOWN, pid); 设置socket所属的进程。F_GETOWN可以得到socket所属的进程或进程组
关于 urgent mark:
TCP支持在普通数据流中接受紧急数据。必须设置socket的选项为SO_OOBINLINE.
可以使用sockatmark来判断当前是否在读urgentmark。
#include<sys/socket.h>
intsockatmark(int sockfd);
Returns: 1 if at mark, 0 if not at mark, -1 on error
最后
- TCP可以在正常数据中接收OOB,也可以单独recv(指定MSG_OOB).
- TCP 只支持一个字节的OOB,后面的会冲掉前面未接收的
关于非阻塞和异步
设置费阻塞模式:
fcntl 打开O_NOBLOCK 开关,这样sendrecv 暂时不能执行的时候返回错误,errno设置EWOULDBLOCK或者 EAGAIN. 然后可以用poll/select/epoll来查询什么时候可以写或读。
异步socket:
当socket可读或者可写的时候会发信号SIGIO,估计也要先设置socket的所属进程F_SETOWN
启用异步的步骤:
- 设置socket所属进程
- fcntl(fd, F_SETOWN, pid)
- ioctl(fd, FIOSETOWN, pid)
- ioctl(fd, SIOCSPGRP, pid)
- 对socket启用异步
- fcntl(fd, F_SETFL, flags|O_ASYNC)
- ioctl(fd, FIOASYNC, &n)
推荐使用fcntl,貌似所有平台都支持。
- apue读书笔记之socket
- APUE读书笔记 之 进程控制
- APUE读书笔记 之 标准I/O库
- APUE读书笔记
- APUE读书笔记
- APUE读书笔记
- APUE读书笔记
- apue读书笔记之大端小端字节序
- APUE读书笔记之二——文件I/O
- APUE读书笔记之四——文件和目录
- APUE读书笔记---进程间通信之POSIX共享内存区
- APUE学习之----socket编程实现简单的C/S
- APUE读书笔记--进程基础
- APUE读书笔记-进程通信
- APUE读书笔记(2)
- APUE 读书笔记 Chapter1
- 读书笔记----APUE(第一章)
- 《apue》读书笔记 停止更新
- 一名应届毕业生对职业生涯规划的求教
- 基于once0.6的高性能socks5服务器:once socks 5
- 开启博客第一篇文章
- android 自定义Adapter的心得
- fff
- apue读书笔记之socket
- Visual Studio 2005 开发 Silverlight 1.0 (转)
- OpenGL黑屏故障总结
- JavaScript V8做为脚本引擎的可行性
- 浅谈三维场景的渲染优化
- 进度条
- js日期控件的代码
- 送给优柔寡断和胡思乱想的朋友们&17条人生哲理
- 黑客精神&黑客守则