域名解析顺序
-
etc/hosts或Windows的hosts
-
etc/resolv.conf中查找域名服务器(DHCP可以自动分配域名服务器)
-
DNS服务器查找IP
gethostbyname() //return struct hostent
struct hostent
{
char *h_name; /*official name of host*/
char **h_aliases; /*alias list*/
int h_addrtype; /*host address type*/
int h_length; /*length of address*/
char **h_addr_list; /*list of addresses*/
}
TCP/IP协议族
1.分层的概念(五层概念模型)
应用层:HTTP(Hypertext Transfer Protocol),FTP(File Transfer Protocol),SMTP(Simple Mail Transfer Protocol),SSH(22),TELNET(23)
传输层:解决进程接受数据 TCP(Transmission Control Protocol),UDP (User Datagram protocol)
网络层:解决网络传输问题 IP(Internet Protocol),ICMP(Internet Control Message Protocol),ARP(Address Resolution Protocol),RARP(Reverse ARP),
LLC层(MAC):解决局域网链路问题 (典型协议ARP)
物理层:PCS(物理编码层)PMA(物理适配层)
常用协议
数据链路层是负责接收IP数据包并通过网络发送,或者从网络上接收物理帧,
抽出IP数据包,交给IP层。
ARP是正向地址解析协议,通过已知的IP,寻找对应主机的MAC地址。
RARP是反向地址解析协议,通过MAC地址确定IP地址。比如无盘工作站还有DHCP服务。
ICMP是网络层的补充,可以回送报文。用来检测网络是否通畅。
Ping命令就是发送ICMP的echo包,通过回送的echo relay进行网络测试。
IP地址转换(本地-网络)
点分十进制(char*)————二进制(int)
本地字节序(小端序)————网络字节序(大端序)
case1:点分十进制————>网络字节序的二进制
in_addr_t inet_addr(const char* cp)
int inet_aton(const char* cp,struct in_addr* inp)
case2:网络字节序的二进制————>点分十进制
char* inet_ntoa(struct in_addr in)
其他转换函数
htons------host to net short
htonl------host to net long
ntohs------net to host short
ntohl------net to host long
子网掩码
24——表示前24位为1后八位为0
255.255.255.0——表示前24位为1后八位为0
作用:将ip地址扩大到ip地址段
HTTP协议(解包)
- 数据包第一步到网卡
- 链路层解包)网卡驱动————MAC包头
- (tcp/ip层解包)内核协议栈————IP/TCP包头
tcp编程
监听句柄————>接收新的链接
链接句柄————>接收新的客户端—accept()阻塞
read()/write()
recvmsg()/sendmsg()
1.create socket创建流式套接字
用法:int sock=socket(协议族,套接字类型,传输协议)
函数原型:int socket(int protofamily,int type,int protocol);//返回socket fd
- 例:ICMP
socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
- 例:SYN
socket(AF_INET,SOCK_RAW,IPPROTO_IP);
协议族:AF_INET AF_INET6 AF_LOCAL AF_ROUTE
套接字类型:SOCK_STREAM SOCK_DGRAM SOCK_RAM
传输协议:IPPROTO_TCP IPPROTO_UDP IPPROTO_SCTP IPPROTO_TIPC
2.用struct sockaddr_in结构体来封装信息
结构体原型:
struct sockaddr_in
{
sin_family;//协议族
sin_port;//端口号(网络字节序二进制)
sin_addr.s_addr;IP地址(网络字节序二进制)
}
源地址赋值
bzero(&connection._addr,sizeof(connection._addr));
connection._addr.sin_family = AF_INET;
通常TCP/UDP 协议源地址和端口都是随机的
INADDR_ANY&0转不转网络字节序无所谓
connection._addr.sin_addr.s_addr = htons(INADDR_ANY);
connection._addr.sin_port = htons(0);
目的地址赋值
bzero(&connection.server_addr,sizeof(connection.server_addr));
connection.server_addr.sin_family = AF_INET;
connection.server_addr.sin_addr.s_addr=inet_addr(server_ip); —inet_addr()的缺陷:必须对-1做检测处理
因为inet_addr()的结果是整型,而发生错误时返回-1。
而 ina.sin_addr.s_addr是unsigned long型
-1在long short显示成111111111,和IP地址255.255.255.255相符合!会被误认为广播地址!
connection.servaddr.sin_port = htons(server_port); —若server_port为char*类型 使用atoi()转换
3.将信息绑定到套接字上bind()
用法:bind(套接字句柄,强转为struct sockaddr*类型的地址,信息的大小);——返回值小于0-失败
函数原型:int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
4.打开监听句柄接收链接信息listen()
listen(套接字句柄,链接个数);——返回值小于0-失败
函数原型:int listen(int sockfd, int backlog);
5.打开连接句柄接收客户端accept()
函数原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);—— 返回连接connect_fd
TCP源码
struct tcphdr {
__be16 source;
__be16 dest;
__be32 seq;
__be32 ack_seq;
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u16 res1:4,
doff:4,
fin:1,
syn:1,
rst:1,
psh:1,
ack:1,
urg:1,
ece:1,
cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u16 doff:4,
res1:4,
cwr:1,
ece:1,
urg:1,
ack:1,
psh:1,
rst:1,
syn:1,
fin:1;
#else
#error "Adjust your <asm/byteorder.h> defines"
#endif
__be16 window;
__sum16 check;
__be16 urg_ptr;
};
IP源码
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4,
version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
__u8 version:4,
ihl:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8 tos;
__be16 tot_len;
__be16 id;
__be16 frag_off;
__u8 ttl;
__u8 protocol;
__sum16 check;
__be32 saddr;
__be32 daddr;
/*The options start here. */
};
UDP编程
recvfrom()/sendto()
广播数据包(广播只在局域网中,不能跨网段)
路由器不会转发广播数据包
交换机会转发广播数据包
广播包的目的地址(mac)为FF:FF:FF:FF:FF:FF
组播数据包(在组播组中进行传播)
路由器可以转发组播数据包
socket选项设置与读取函数
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);
udp_group_broadcast_recv
-
创建和绑定UDP
-
将当前UDP加入到组播组中
-
recvfrom()接收到组播组其他成员的消息
udp_group_broadcast_send
-
创建和绑定UDP
-
sendto()发送消息到组播组其他成员(需要传入当前的地址peeraddr)
组播结构体
struct ip_mreq
{
struct in_addr imr_multiaddr;/*multicast group to join*/
struct in_addr imr_interface;/*interface to join one*/
}
//多播组的IP地址
//加入的客户端主机IP地址
相关函数原型
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);