一。
1.一个长时间运行的程序,即守护进程,它只在响应来自网络的请求时才发送网络消息。
2.通常一个客和每次只与一个服务器通信,不过以web浏览器为例子,该客户端程序却可以与多个不同的web服务器通信。
3.tcp/ip 协议簇 ,也称为“网际协议簇“
4.英特网 和 网际网
*因特网是一个网际网
*网际网是采用tcp/ip协议通信所连通的网络。
*因特网只有一个,全球具有地址唯一性。不属于因特网的网际是可以是任何一个节点分配地址。
*一个进程关闭会关闭它所打开的所有描述符(文件、socket、pipe等),即将结束的程序,也可以不close(fd)的。不过通常我们都close()
5.bzero 比 memset 更好记忆。 因为memset参数如果搞乱了,memset都检查不出来,因为都是int类型。bzero(&add, sizeof(add) );
6.inet_pton() 支持ipv6的ip地址转换器。 inet_add()旧的。
7.之所以ip要使用通用的struct sockaddr* ,是因为套接字函数早于ANSIC标准,void*还不可用,否则我们可以用void*表示任何数据结构。
8.tcp是一个没有字符边界的字节流,源源不断,udp则有其数据边界结尾。
9.tcp传输层的数据单元叫分节,如果分节大于发送缓冲区,则分段进行发送。
1.read()不能确保一次性能读完all the data,所以我们应确保它能在循环中一直读取数据直到read返回0或负值才结束对数据的接收读取。
对于客户端:服务器close(fd)表示数据结束
对于服务端:客户端close(fd)表示数据发送完毕或请求结束。
errno值不应该用于多线程的全局变量来记录。因为是多线程的。嘻嘻
2.unix在一个进程终止时总是关闭该进程所有打开的描述符。
3.传输层:分节 , 网路层:ip数据报,链路层:祯,物理层:bit传输咯。 除了物理层,这些单元是越来越大呀。
4.tcp/ip协议族,为提高效率,应尽可能避免ip的分层与重组操作。
5.ipv4数据报最大65535,ipv6最大65575
避免被另一个函数集细节把网络编程讨论搞负杂了。
6.错误处理:包裹函数。 它很少是程序性能的瓶颈所在。
7.每个包裹函数完成实际的函数调用,检查返回值,并在发生错误时终止进程。大写开头的函数。
8.线程函数出错时并不把错误返回给主调,而是通过设置errno值返回。
9.INADDR_ANY表示多个网络接口和主机进程可以在任意网络接口上接受客户链接
1.snprintf() 比 sprintf()要好,因为sprintf()不检查缓冲区溢出。fgets, strncat ,strncpy,strlcat, strlcpy
2.size_t类似的数据类型的定义,其实是为了更好的融合32,64位机,为了可移植性嘛
二。
*传输层tcp ,udp,sctp ,udp是一个无连接的协议哦。
1.udp:每个数据都有一个长度,该长度随数据一起发送到目标端。因为他是无连接的。
udp每发送一个数据包都会创建链接,发送,释放链接。如果udp调用connect的话呢,那么内核就记住第一次对端的ip/port,这样之后就不需要总是创建和释放链接,直接发送数据即可。
2.tcp . 1 对 多 , udp. 多 对 多
3.tcp如果没有收到确认,就自动重传并延长等待时间。
4.流量控制--》通告窗口:接收缓冲的容量
5.ipv4 32位,ipv6 128位
6.3次握手:
1.客发syn j
2.服回ack , syn j+1
3.客回ack j+1+1
7.tcp选项:
1.最大分节大小:TCP_MAXSEG
2.最大窗口大小:SO_RCVBOF
四次终止:
close() ------> fin,j
<-----ACK j+1
<------FIN,n
------->ACK n+1; (time_waite为了处理该ack丢失的情况)
主动发起close的在这里进入time_wait状态,因为他要确保对面的挂,他要保证万一这个ack在途中阻塞等一系列情况,让ack到达对方,避免过期。然后他自己会过一段时间挂掉。
8.TCP状态转换:
CLOSE-------------------------LISTEN
SYN_SEND--------------------SYN_RCVD
ESTABLISHED----------------ESTABLISHED
FIN_WAITE_1------------------------CLOSE_WAITE
FIN_WAITE_2-------------------------LAST_ACK
TIME_WAITE--------------------------CLOSED
CLOSED
9. 2MSL最大分节生命期的2倍时长,msl在因特网中存活最长的ip数据报。
1.全双工:是两条独立的链接,并非一条共用的来回链接。
三。
1.端口号:
*端口号可以区分进程使用的多种不同的协议tcp,udp
* 0--1023 属于进程端口
* 1024---49151已登记端口号:用来给服务端程序使用
* 49152--65535动态端口号:给客户程序的临时端口号
2.标识每个端点的两个值(ip,端口对)通常称为一个套接字。 4元素才能确定消息目标与起始。
3.tcp必须为已发送的数据保留一个副本。直到他被对端确认为止。。。。然后才丢弃。
4.udp是不可靠的,因此无需缓冲区。
5.write成功仅仅表示:数据已成功加入到链路层的输出队列,并不代表对方接收成功。
6.主动执行关闭的那一端,是历经TIME_WAIT状态的那一端。 -------- 为了处理最终的哪一个ACK丢失的情况。
四。
基本套接字编程
1.tcp,udp的ip与port在套接字地址结构中总是以网络字节序来存储的。
2.地址结构:内核会把地址先转成struct sockaddr *,通用结构再取出其中sa_family字段来确定是哪种类型的地址。
3.从进程到内核传递套接字地址结构的函数有3个:bind , connect , sendto
4.内核 到 进程 :accept recvfrom getsockname getpeername
5.字节排序:小端 大端 ----》网络字节序列。主机字节序列。
6.在大端系统中,这些字节排序函数通常被定义为空宏。 htons htonl ntohs ntohl()
7.客户端不用bind(),内核则会确定源地址,且会选择一个临时端口。
8.调getsockname()可得到临时端口信息。
9.Listen().内核为任何一个给定的监听套接字维护两个队列:未完成链接的队列,已完成链接的队列。
1.accept()第二、三个参数为空指针表示我们对客户不关心。 (0---1023端口的bind必须以root身份bind)
2.close(fd) 仅仅是引用计数减1罢了。直到0才真正释放。
3.getsockname()本地信息,getpeername()外地信息 (ip,port)
4.一个信号处理函数运行期间,正被递交的信号是阻塞的。
5.如果一个信号在被阻塞期间产生了一次或多次,那么该信号被解阻塞后,通常只递交一次:信号默认是不排队的。
6.unix关机时,init进程会给所有进程发送sigterm信号以关闭,过一段时间再发sigkill信号;sigkill信号是无法被捕获的。
7.以文本串方式传递数据会比较好,因为客----服 就解释二进制序列不一致。因为小端大端不同的问题导致。
8.I/O复用,处理多个描述符select() poll(),不因为一个描述符而阻塞其他描述符的数据交流。
9.输入操作:1.等待数据准备好 2.从内核向进程复制数据。进程----》内核复制
*阻塞I/O
*非阻塞I/O
*I/O复用
信号驱动式I/O模型----由信号来处理
异步I/O模型------------告之内核处理,处理完了让它通知过来/。
五。
*套接字选项
1.fcntl()设置非阻塞 或 信号驱动式I/o,设置属性
2.getsockopt() setsockopt()
3.Tcp已连接套接字会从监听套接字继承过来。
4.fcntl:235page or 183page .
常用的选项:SO_keepalive so_rcvbuf so_sndbuf so_reuseaddr
六。
UDP套接字编程 187
sendto() recvfrom()
一般来说,大多数tcp服务器是并发的,udp是迭代的。
2.udp的connect()能够提高效率,避免每个包都建立链接和释放链接。
七。
名字与地址转换:
gethostbyname() gethostbyaddr(0 getserverbyname() getserverbyport() getaddrinfo() getnameinfo()