网络编程第六天
一、常用调试测试工具
使用telnet测试TCP服务器端
使用lsof
使用tcpdump
使用netstat
使用sniffer
使用wireshark
Chariot
…
SmartBit—硬件
二、网络信息检索函数
gethostname() 获得主机名
getpeername() 获得与套接口相连的远程协议地址
getsockname() 获得本地套接口协议地址
gethostbyname() 根据主机名取得主机信息
gethostbyaddr() 根据主机地址取得主机信息
getprotobyname() 根据协议名取得主机协议信息
getprotobynumber() 根据协议号取得主机协议信息
getservbyname() 根据服务名取得相关服务信息
getservbyport() 根据端口号取得相关服务信息
三、网络属性设置
getsockopt和setsockopt
int getsockopt(int sockfd,int level,int optname,void *optval,socklen_t *optlen)
int setsockopt(int sockfd,int level,int optname,const void *optval,socklen_t *optlen)
level指定控制套接字的层次.可以取三种值:
1)SOL_SOCKET:通用套接字选项.
2)IPPROTO_IP:IP选项.
3)IPPROTO_TCP:TCP选项.
optname指定控制的方式(选项的名称),我们下面详细解释
optval获得或者是设置套接字选项.根据选项名称的数据类型进行转换
四、网络超时
设置socket的属性 SO_RCVTIMEO
参考代码如下
struct timeval tv;
tv.tv_sec = 5; // 设置5秒时间
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv,
sizeof(tv)); // 设置接收超时
recv() / recvfrom() // 从socket读取数据
用select检测socket是否’ready’
参考代码如下
struct fd_set rdfs;
struct timeval tv = {5 , 0}; // 设置5秒时间
FD_ZERO(&rdfs);
FD_SET(sockfd, &rdfs);
if (select(sockfd+1, &rdfs, NULL, NULL, &tv) > 0) // socket就绪
{
recv() / recvfrom() // 从socket读取数据
}
设置定时器(timer), 捕捉SIGALRM信号
参考代码如下
void handler(int signo) { return; }
struct sigaction act;
sigaction(SIGALRM, NULL, &act);
act.sa_handler = handler;
act.sa_flags &= ~SA_RESTART;
sigaction(SIGALRM, &act, NULL);
alarm(5);
if (recv(,,,) < 0) ……
五、OOB带外数据和广播、组播
TCP 上没有真正意义上的“带外数据”
TCP 由 “紧急模式”的方法来传
发送方:设置URG选项
接收方:收到包含URG的TCP数据设置带外数据标志指针->指针指向带外数据位置
发送:
send(int sockfd, void *buf, int len, int flags);
其中flags设置为MSG_OOB
接收:
Recv(int sockfd, void *buf, int len, int flags);
其中flags设置为MSG_OOB
广播
前面介绍的数据包发送方式只有一个接受方,称为单播
如果同时发给局域网中的所有主机,称为广播
只有用户数据报(使用UDP协议)套接字才能广播
广播地址
以192.168.1.0 (255.255.255.0) 网段为例,最大的主机地址192.168.1.255代表该网段的广播地址
发到该地址的数据包被所有的主机接收
255.255.255.255在所有网段中都代表广播地址
创建用户数据报套接字
缺省创建的套接字不允许广播数据包,需要设置属性
setsockopt可以设置套接字属性
接收方地址指定为广播地址
指定端口信息
发送数据包
int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
头文件:<sys/socket.h>
level : 选项级别(例如SOL_SOCKET)
optname : 选项名(例如SO_BROADCAST)
optval : 存放选项值的缓冲区的地址
optlen : 缓冲区长度
返回值:成功返回0 失败返回-1并设置errno
sockfd = socket(,,);
……
int on = 1;
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
……
sendto(;;;;;);
组播
单播方式只能发给一个接收方。
广播方式发给所有的主机。过多的广播会大量占用网络带宽,造成广播风暴,影响正常的通信。
组播(又称为多播)是一种折中的方式。只有加入某个多播组的主机才能收到数据。
多播方式既可以发给多个主机,又能避免象广播那样带来过多的负载(每台主机要到传输层才能判断广播包是否要处理)
网络地址
A类地址
第1字节为网络地址,其他3个字节为主机地址。第1字节的最高位固定为0
1.0.0.1 – 126.255.255.255
B类地址
第1字节和第2字节是网络地址,其他2个字节是主机地址。第1字节的前两位固定为10
128.0.0.1 – 191.255.255.255
C类地址
前3个字节是网络地址,最后1个字节是主机地址。第1字节的前3位固定为110
192.0.0.1 – 223.255.255.255
D类地址(组播地址)
不分网络地址和主机地址,第1字节的前4位固定为1110
224.0.0.1 – 239.255.255.255
![在这里插入图片描述](https://img-blog.csdnimg.cn/4d0270181d4f42deb287d7e1dbd67897.png)
struct ip_mreq
{
struct in_addr imr_multiaddr;
struct in_addr imr_interface;
};
struct ip_mreq mreq;
bzero(&mreq, sizeof(mreq));
mreq.imr_multiaddr.s_addr = inet_addr(“224.10.10.1”);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
inet_pton(AF_INET,”192.168.7.89”, (void *)& mreq.imr_interface);
setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
sizeof(mreq));
六、UNIX域套接字
socket同样可以用于本地通信
创建套接字时使用本地协议PF_UNIX(或PF_LOCAL)。
socket(AF_LOCAL, SOCK_STREAM, 0)
socket(AF_LOCAL, SOCK_DGRAM, 0)
分为流式套接字和用户数据报套接字
和其他进程间通信方式相比使用方便、效率更高
常用于前后台进程通信
本地地址结构
struct sockaddr_un // <sys/un.h>
{
sa_family_t sun_family;
char sun_path[108]; // 套接字文件的路径
};
填充地址结构
struct sockaddr_un myaddr;
bzero(&myaddr, sizeof(myaddr));
myaddr.sun_family = AF_UNIX; strcpy(myaddr.sun_path, “/tmp/mysocket”);
服务器端
socket(AF_UNIX, SOCK_STREAM, 0)
bind(,本地地址, )
listen(,)
accept(,,)
recv() / send()
……
客户端
socket(PF_UNIX, SOCK_STREAM, 0)
bind(,本地地址, ) // 可选
connect(,,)
recv() / send()
……