《Unix网络编程》卷一(简介TCP/IP、基础套接字编程)
通常说函数返回某个错误值,实际上是函数返回值为-1,而全局变量errno被置为指定的常值(即称函数返回这个错误值)。
exit终止进程,Unix在一个进程终止时总是关闭该进程所有打开的描述符。
TCP三次握手完毕,accept返回,其返回值是一个称为已连接描述符(connected descriptor)的新描述符。调用close关闭与客户的连接。
套接字API。
TCP状态转移图,11种状态。
MSS,maximum segment size,最大分节大小。通常客户端主动打开时发送SYN的同时会发送MSS,服务端应答(SYN、ACK、MSS)时同样也发送一个MSS,不同方向上MSS可以不同。
SCTP多宿特性,单个SCTP端点能支持多个IP地址。
SCTP的四路握手。验证标记、状态cookie。
IPv4数据报最大长度65535,包括IP首部,因为总长度字段是16位;IPv6数据报最大长度65575,包括40字节IPv6首部,因为净长度字段是16位。
IPv4首部20字节(固定长度),另外还有最多40字节可选部分。
套接字地址结构在内核和进程间传递,从进程传到内核,从内核传到进程,不是非常理解,应该就是参数传递进去和被写回吧?另外有一个值-结果参数以前很少碰到。
每个文件或套接字都有一个引用计数,引用计数在文件表项中维护。
存放在硬盘上的可执行程序文件能被Unix执行的唯一方法是:由一个现有进程调用六个exec函数中的一个。(理解)
六个exec函数区别在于:待执行程序由文件名还是路径名指定;参数是一一列出还是指针数组;把调用进程环境传递给新程序还是指定新环境。
子进程调用exec时,子进程内存映像被替换成新程序文件,只有文件描述符(在socket中是已连接套接字描述符)跨exec继续保持开放。
一个简单echo客户/服务器程序涉及到的一些细节(非常重要):
僵死子进程,通过捕获SIGCHLD信号加以处理;
信号处理函数必须调用waitpid而不是wait,因为unix信号是不排队的,当有多个子进程时wait函数只能处理第一个,后面的将变成僵死进程;
另一个问题是服务器进程终止时,客户进程没被告知,因为客户进程阻塞于等待用户输入而未接收到通知,这需要select或poll函数来处理,它们等待多个描述符中的任何一个就绪而不是阻塞于某个描述符。
select函数中间的三个参数(读、写、异常描述符集)都是值—结果参数,返回时,未就绪描述符对应的被置0,其他是1,重新调用时,将所关心位重置1。
close函数有两个限制,shutdown函数可以克服,它关闭一半tcp连接(可参数选读或者写)。
pselect时间参数结构不同;另一个不同点是多了一个指向信号掩码的指针,从而运行程序先禁止提交某些信号。
拒绝服务(denial of service,DoS)型攻击。
UDP也可以使用connect函数,成为已连接UDP套接字,然后可以使用write和read函数读写,而不是sento和recvfrom。
DNS中的条目称为资源记录(resource record,RR)。常见RR类型有:A、AAAA、PTR、MX、CNAME。
gethostbyname和gehostbyaddr的返回值均为一个hostent(host entry缩写)结构:
- struct hostent {
- const char *h_name; // 主机的正式名称。
- char **h_aliases; // 空字节-地址的预备名称的指针。
- short h_addrtype; // 地址类型; 通常是AF_INET。
- short h_length; // 地址的比特长度
- char **h_addr_list; // 主机网络地址指针(只有IPV4)
- #define h_addr h_addr_list[0] // h_addr 为 h_addr_list中的第一地址。
- };
gethostbyname只能返回IPV4地址,而getaddrinfo能够同时处理IPV4和IPV6地址。
gethostbyname和gehostbyaddr用于主机名和地址的映射,而getservbyname和getservbyport则用于服务与端口之间的映射。
getaddrinfo能处理名字到地址、服务到端口的转换(由参数中列表中第一个为主机名,第二个为服务名可看出):
- int getaddrinfo( const char *hostname,
- const char *service,
- const struct addrinfo *hints,
- struct addrinfo **result );//返回结果保存到这里
其中,保存返回结果的struct addrinfo结构体详细信息如下:
- 表头文件: #include<netdb.h>
- struct addrinfo
- {
- int ai_flags;
- int ai_family; //AF_INET,AF_INET6,UNIX etc
- int ai_socktype; //STREAM,DATAGRAM,RAW
- int ai_protocol; //IPPROTO_IP, IPPROTO_IPV4, IPPROTO_IPV6 etc
- size_t ai_addrlen;//length of ai_addr
- char* ai_canonname; //full hostname
- struct sockaddr* ai_addr; //addr of host
- struct addrinfo* ai_next;
- }
- value of ai_falgs:
- AI_PASSIVE: Socket address is intended for `bind'.
- AI_CANONNAME:Request for canonical name.
- AI_NUMERICHOST: Don't use name resolution.
- AI_V4MAPPED: IPv4 mapped addresses are acceptable.
- AI_ALL: Return IPv4 mapped and IPv6 addresses.
- AI_ADDRCONFIG:Use configuration of this host to choose
- 定义函数:
- int getaddrinfo( const char *hostname, const char *service, const struct addrinfo *hints,
- struct addrinfo **result );
- 函数说明:
- getaddrinfo函数能够处理名字到地址以及服务到端口这两种转换,返回的是一个sockaddr 结构的链而 不是一个地址清单。它具有协议无关性。
- hostname:一个主机名或者地址串(IPv4的点分十进制串或者IPv6的16进制串)
- service:一个服务名或者10进制端口号数串。
- hints:可以是一个空指针,也可以是一个指向某个addrinfo结构的指针,调用者在这个结构中填入关于期望返回的信息类型的暗示。举例来说:如果指定的服务既支持TCP也支持UDP,那么调用者可以把hints结构中的ai_socktype成员设置成SOCK_DGRAM使得返回的仅仅是适用于数据报套接口的信息。返回0: 成功,返回非0: 出错。
- 定义函数:const char *gai_strerror( int error );
- 函数说明:
- 该函数以getaddrinfo返回的非0错误值的名字和含义为他的唯一参数,返回一个指向对应的出错信息串的指针。
- 定义函数: void freeaddrinfo( struct addrinfo *ai );
- 函数说明:
- 由getaddrinfo返回的所有存储空间都是动态获取的,这些存储空间必须通过调用freeaddrinfo返回给系统。
struct addrinfo结构体
与getaddrinfo函数对应的是getnameinfo函数。
- 在linux环境下,结构体struct sockaddr在/usr/include/linux/socket.h中定义,具体如下:
- typedef unsigned short sa_family_t;
- struct sockaddr {
- sa_family_t sa_family; /* address family, AF_xxx */
- char sa_data[]; /* 14 bytes of protocol address */
- 在linux环境下,结构体struct sockaddr_in在/usr/include/netinet/in.h中定义,具体如下:
- /* Structure describing an Internet socket address. */
- struct sockaddr_in
- {
- __SOCKADDR_COMMON (sin_);
- in_port_t sin_port; /* Port number. */
- struct in_addr sin_addr; /* Internet address. */
- /* Pad to size of `struct sockaddr'. */
- unsigned char sin_zero[sizeof (struct sockaddr) -
- __SOCKADDR_COMMON_SIZE -
- sizeof (in_port_t) -
- sizeof (struct in_addr)];
- /* 字符数组sin_zero[8]的存在是为了保证结构体struct sockaddr_in的大小和结构体struct sockaddr的大小相等 */
- };
- struct sockaddr是通用的套接字地址,而struct sockaddr_in则是internet环境下套接字的地址形式,二者长度一样,都是16个字节。二者是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr。一般情况下,需要把sockaddr_in结构强制转换成sockaddr结构再传入系统调用函数中。
- 下面是struct sockaddr_in中用到两个数据类型,具体定义如下:
- /* Type to represent a port. */
- typedef uint16_t in_port_t;
- struct in_addr其实就是32位IP地址
- struct in_addr {
- unsigned long s_addr;
- };
- BSD网络软件中包含了两个函数,用来在二进制地址格式和点分十进制字符串格式之间相互转换,但是这两个函数仅仅支持IPv4。
- in_addr_t inet_addr(const char *cp);
- char *inet_ntoa(struct in_addr in);
- 功能相似的两个函数同时支持IPv4和IPv6
- const char *inet_ntop(int domain, const void *addr, char *str, socklen_t size);
- int inet_pton(int domain, const char *str, void *addr);
- 通常的用法是:
- int sockfd;
- struct sockaddr_in my_addr;
- sockfd = socket(AF_INET, SOCK_STREAM, );
- my_addr.sin_family = AF_INET; /* 主机字节序 */
- my_addr.sin_port = htons(MYPORT); /* short, 网络字节序 */
- my_addr.sin_addr.s_addr = inet_addr("192.168.0.1");
- bzero(&(my_addr.sin_zero), ); /* zero the rest of the struct */
- //memset(&my_addr.sin_zero, 0, 8);
- bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));
- #define UNIX_PATH_MAX 108
- struct sockaddr_un {
- sa_family_t sun_family; /*PF_UNIX或AF_UNIX */
- char sun_path[UNIX_PATH_MAX]; /* 路径名 */
- };
- struct sockaddr结构类型是用来保存socket信息的:
- struct sockaddr {
- unsigned short sa_family; /* 地址族, AF_xxx */——地址的格式
- char sa_data[]; /* 14 字节的协议地址 */——地址值(IP和端口号)
- };
- Sockfd是调用socket函数返回的socket描述符,my_addr是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;addrlen常被设置为sizeof(struct sockaddr)。
- struct sockaddr结构类型是用来保存socket信息的:
- struct sockaddr {
- unsigned short sa_family; /* 地址族, AF_xxx */
- char sa_data[]; /* 14 字节的协议地址 */
- };
- sa_family一般为AF_INET,代表Internet(TCP/IP)地址族;sa_data则包含该socket的IP地址和端口号。
- 另外还有一种结构类型:
- struct sockaddr_in {
- short int sin_family; /* 地址族 */
- unsigned short int sin_port; /* 端口号 */
- struct in_addr sin_addr; /* IP地址 */
- unsigned char sin_zero[]; /* 填充0 以保持与struct sockaddr同样大小 */
- };
- 这个结构更方便使用。sin_zero用来将sockaddr_in结构填充到与struct sockaddr同样的长度,可以用bzero()或memset()函数将其置为零。指向sockaddr_in 的指针和指向sockaddr的指针可以相互转换,这意味着如果一个函数所需参数类型是sockaddr时,你可以在函数调用的时候将一个指向 sockaddr_in的指针转换为指向sockaddr的指针;或者相反。
- 你只要记住,填值的时候使用sockaddr_in结构,而作为函数的
- 参数传入的时候转换成sockaddr结构就行了,毕竟都是16个字符
- 长。
- struct in_addr {
- union {
- struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
- struct { u_short s_w1,s_w2; } S_un_w;
- u_long S_addr;
- } S_un };
struct sockaddr与struct sockaddr_in ,struct sockaddr_un的区别和联系
- inet_pton函数将点分十进制格式IP地址转换为二进制整数,IPV4和IPV6都支持:
- inet_pton:将“点分十进制” -> “二进制整数”
- int inet_pton(int af, const char *src, void *dst);
- 这个函数转换字符串到网络地址,第一个参数af是地址簇,第二个参数*src是来源地址,第三个参数* dst接收转换后的数据。
- inet_pton 是inet_addr的扩展,支持的多地址族有下列:
- af = AF_INET
- src为指向字符型的地址,即ASCII的地址的首地址(ddd.ddd.ddd.ddd格式的),函数将该地址转换为in_addr的结构体,并复制在*dst中。
- af = AF_INET6
- src为指向IPV6的地址,函数将该地址转换为in6_addr的结构体,并复制在*dst中。
- 如果函数出错将返回一个负值,并将errno设置为EAFNOSUPPORT,如果参数af指定的地址族和src格式不对,函数将返回0。
《Unix网络编程》卷一(简介TCP/IP、基础套接字编程)的更多相关文章
- 20181225 基于TCP/IP和基于UDP/IP的套接字编程
一.TCP/IP的套接字编程 服务器端代码: import socketserver = socket.socket() # 默认是基于TCP# 基于TCP的对象serve=socket.sock ...
- Java 网络编程(五) 使用TCP/IP的套接字(Socket)进行通信
链接地址:http://www.cnblogs.com/mengdd/archive/2013/03/10/2952616.html 使用TCP/IP的套接字(Socket)进行通信 套接字Socke ...
- 网络编程之TCP三次握手与四次挥手、基于TCP协议的套接字编程
目录 TCP三次握手和四次挥手 背景描述 常用的熟知端口号 TCP概述 TCP连接的建立(三次握手) TCP四次挥手 如果已建立连接,客户端突然断开,会怎么办呢? 基于TCP协议的套接字编程 什么是S ...
- 【Python网络编程】利用Python进行TCP、UDP套接字编程
之前实现了Java版本的TCP和UDP套接字编程的例子,于是决定结合Python的学习做一个Python版本的套接字编程实验. 流程如下: 1.一台客户机从其标准输入(键盘)读入一行字符,并通过其套接 ...
- 使用TCP/IP的套接字(Socket)进行通信
http://www.cnblogs.com/mengdd/archive/2013/03/10/2952616.html 使用TCP/IP的套接字(Socket)进行通信 套接字Socket的引入 ...
- TCP和UDP套接字编程 (java实现)
在了解网络编程之前,我们先了解一下什么叫套接字 套接字即指同一台主机内应用层和运输层之间的接口 由于这个套接字是建立在网络上建立网络应用的可编程接口 因此也将套接字称为应用程序和网络之间的应用程序编程 ...
- 《Unix 网络编程》08:基本UDP套接字编程
基本UDP套接字编程 系列文章导航:<Unix 网络编程>笔记 UDP 概述 流程图 recvfrom 和 sendto #include <sys/socket.h> ssi ...
- python 之 网络编程(基于TCP协议的套接字通信操作)
第八章网络编程 8.1 基于TCP协议的套接字通信 服务端套接字函数 s.bind() 绑定(主机,端口号)到套接字 s.listen() 开始TCP监听 s.accept() 被动接受TCP客户的连 ...
- 【转】 VC中TCP实现 异步套接字编程的原理+代码
所谓的异步套接字编程就是 调用了 如下函数 WSAAsyncSelect 设置了 套接字的状态为异步,有关函数我会在下面详细介绍... 异步套接字解决了 套接字编程过程中的堵塞问题 .... ...
- 网络编程之基于UDP协议的套接字编程、基于socketserver实现并发的socket
目录 基于UDP协议的套接字编程 UDP套接字简单示例 服务端 客户端 基于socketserver实现并发的socket 基于TCP协议 server类 request类 继承关系 服务端 客户端1 ...
随机推荐
- mac终端命令大全全全全全全全全全
OSX 的文件系统 OSX 采用的Unix文件系统,所有文件都挂在跟目录 / 下面,所以不在要有Windows 下的盘符概念. 你在桌面上看到的硬盘都挂在 /Volumes 下. 比如接上个叫做 US ...
- BizTalk动手实验(五)Map开发测试
1 课程简介 通过本课程熟悉Map的相关开发与测试技术 2 准备工作 熟悉XML.XML Schema.XSLT等相关XML开发技术 新建BizTalk空项目 演示 3.1 基本操作 打开MapDev ...
- IOS第18天(9,核心动画-动画组)
****动画组 // 核心动画都是假象,不能改变layer的真实属性的值// 展示的位置和实际的位置不同.实际位置永远在最开始位置 #import "HMViewController.h&q ...
- A trip through the Graphics Pipeline 2011_05
After the last post about texture samplers, we’re now back in the 3D frontend. We’re done with verte ...
- gdb调试,自动显示多个变量的值
调试程序的时候有时候要一行监控多个变量的值, 可以这样写: p {var1, var2, var3} 要跟踪程序自动显示,可以使用display display {var1, var2, var3}要 ...
- 滚动固定TAB在顶部显示
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...
- shell读取文件每行,并执行命令
#!/bin/bash while read line do $line & done < /path/filename
- 1CSS与文档
层叠样式表(Cascading Style Sheet,CSS)的功能十分强大,可以影响一个或一组文档的表现. 为什么结构化对HTML来说很重要:1.非结构化页面使得建立内容索引极为困难.2.缺乏结构 ...
- 在项目里交叉使用Swift和OC【转】
Swift and Objective-C in the Same Project在项目里交叉使用Swift和OC Swift与OC的兼容性使得你可以在项目里使用Swift+OC的方式编写应用程序,称 ...
- CentOS6修改主机名(hostname)及 修改/etc/hosts 文件,增加ip和hostname的映射关系(转)
CentOS修改主机名(hostname) 需要修改两处:一处是/etc/sysconfig/network,另一处是/etc/hosts,只修改任一处会导致系统启动异常.首先切换到root用户. ...