《TCP/IP网络编程》知识点整理

详细总结了TCP/IP网络编程中的关键概念,包括套接字类型、网络字节序、TCP/UDP实现、多进程服务器、I/O复用、epoll等重要内容。

《TCP/IP网络编程书籍》知识点整理

  1. 理解网络编程和套接字

  2. 套接字类型与协议设置

  3. 地址族与数据序列

    1. 网络字节序是大端,本地是小端,大端是把最后的字节放前面,小端是最后的字节放后面
    2. h代表host,n代表networt。这些是大小端转换的函数,short4B,long8B。
      1. unsigned short tons(unsigned short)
      2. unsigned short ntohs(unsigned short)
      3. unsigned long htonl(unsigned long)
      4. unsigned long ntohl(unsigned long)
    3. p代表presentation,n代表network。这些函数是字符串(点分10进制)转网络字节序地址(8B)的。
      • int inet_pton(int af, const char *src, void *dst)
      • 返回1成功,返回0是ip地址格式不对,返回-1时af不对。
        • af一般是宏确定,ipv4的是AF_INET
      • 传入参数时src,字符串类型(点分10进制)
      • 穿出参数是dst,一般复制给sockaddr_in中的sin_addr.s_addr上
      • const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
        • 成功返回字符串指针,若出错则为NULL
        • src是传入参数,是网络字节序2进制的,一般是sockaddr_in中的sin_addr.s_addr
        • dst是传出参数,是字符串(点分10进制)
  4. 基于TCP(1) 这章是告诉你怎么实现socket

    • TCP不存在数据边界,可以用一个回应来接收好多条传输
    • 注意TCP连接是有奇数个socket,一个监视(socket)加上一对会话或者几对会话(accept)。
    1. int socket(int domain, int type, int protocol)
      • domain 判断是什么协议 ipv4
      • type 用什么流 stream 一般是tcp
      • protocol 默认用0
    2. int bind(int socket, const struct sockaddr *address, socklen_t address_len)
      • socket 标志符
      • address 传入参数,里面有ip地址端口号协议等
      • address_len 顾名思义address的大小
    3. int listen(int socket, int backlog)
      • socket 标志符
      • backlog 最大连接数
    4. int accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len)
      • socket 标志符
      • address 传出参数,里面有客户端的ip地址端口号协议等
      • address_len 顾名思义address的大小
    5. read()/write()
    6. int close(int fildes)
  5. 基于TCP(2) 这章是实践,做一个回声服务端和客户端。

  6. 基于UDP

    1. 存在数据边界

    2. 1
      2
      
      int socket(PF_INET, SOCK_DGRAM, 0);
      int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
      
      1. 创建
    3. 1
      
      ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);//发送
      
      • sockfd用socket创建出来的数
      • buf要发送的缓存数据
      • len要发送的长度
      • flags可选参数, 默认0
      • dest_addr有目的地址的结构体
      • addrlen结构体长度
    4. 1
      
      ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);//接收
      
      • sockfd用socket创建出来的数
      • buf要发送的缓存数据
      • len要发送的长度
      • flags可选参数, 默认0
      • dest_addr有目的地址的结构体
      • addrlen结构体长度
  7. 断开套接字

    1. int shutdown(int sock, int howto) 半关闭函数
      • sock文件描述符
      • howto 关闭什么
        • SHUT_RD 断开输入
        • SHUT_WR 断开输出
        • SHUT_RDWR 断开IO流
          • 相当于第一次调用RD,第二次调用WR。
    2. 这个函数不管什么模式,都会向客户端传送EOF,也就是结束标志
    3. 存在的意义就是让客户端知道要断开了,但还可以收到消息。
  8. 域名及网络地址

    1. nelookup 可以用域名查看ip地址
    2. struct hostent _ gethostbyname(const char _ hostname)
      • struct hostent
        • char * h_name 官方域名
        • char ** h_aliases 其他的许多域名(所以是二级指针)
        • int h_addrtype 地址类型ipv4,ipv6
        • int h_length ipv4 4字节,ipv6 6字节
        • char ** h_addr_list 许多对应的ip地址(所以是二级指针)
          • 这里面的ip地址需要转换才能看懂
          • inet_pton()
      • 失败返回NULL
    3. struct hosting _ gethostbyaddr(const char _ addr, sickle_t len ,int family)
      • addr 结构体指针,里面有ip地址
        • 里面的ip地址要转换成网络字节序
        • inet_ntop()
      • len addr的字节数
      • family ipv4是AF_INET,ipv6是AF_INET6
  9. socket的多种可选项,其中getsockopt是看选项的,setsockopt是设置的。

    1. 可以改变缓冲区大小,但也是大概改,并不一定就是那个数,因为操作系统会二次调整一下
    2. 可以在time-wait时, 是端口复用, 但端口还是在time-wait的, 以便下次还可以同一个端口再次通信。
      1. time-wait在服务端先挥手时会出现,就是4次挥手的倒数2次之后,倒数1次之前。
      2. 因为你最后的那个ACK数据包,你虽然发出去了,但你也不知道他收没收到,所以你怎么判断,你要等一段时间,看看客户端是否再次给你发了一个FIN包,如果没有,那么成功,如果有那就是失败,你需要再发一个包才能断开。所以你要等一段时间去判断。
      3. time-wait会都存在于客户端与服务端,只要谁先请求断开,他就会time-wait,但一般不关心客户端的time-wait,因为客户端再次连接时,会随机一个端口连接,就对于用户透明了。
      4. timeWait
  10. 多进程服务端,显而易见,服务端要能同事服务好多客户端,所以多进程有用

    1. fork()创建子进程,父进程返回进程号(PID),子进程返回0。
    2. 子进程继承父亲的所有东西,包括堆、栈等。
    3. 僵尸进程的产生是由于,如果要回收子进程,要先结束父进程,所以中途子进程结束,父进程没有结束的间隙,子进程没用了,就叫僵尸进程
      1. wait()阻塞,等待子进程结束
      2. Waited()不阻塞,轮训子进程结束
    4. 信号,因为上面两种方式不合适,所以要用信号,我理解就是中断。
      1. alarm()函数能够定时,到时间后能引起信号。
      2. Sigaction()比signal()函数更加稳定,并且在不同的Unix系统中,功能都一样。
      3. 可以传递给Sigaction()函数指针,第一个参数是信号类型。
        1. SIGALRM 到时间了alarm()
        2. SIGINT 输入ctrl+C
        3. SIGCHLD 子进程终止
    5. 子进程和父进程都有套接字描述符时,子进程和父进程要把服务端的两个描述符,一共四个描述符都close()掉,才能关闭那个socket
      1. 根据黑马linux网络编程又知道了一个观点
        1. 子进程会继承父进程的文件描述符, 但之后不会再通信了,应该就是两个文件描述符了
        2. shutdown()是关闭服务端的客户端通信套接字, close是关闭文件描述符
        3. 所以如果子进程和父进程要关闭socket,要调用close4次
        4. 黑马linux网络编程_shutdown
  11. 进程间通信–管道

    1. int pipe(int filedes[2])
      1. 成功返回0,失败返回-1
      2. filedes[0]是文件描述符出口,filedes[1]是文件描述符入口
      3. 读取的时候没有数据的话,是阻塞的
      4. 读取完成后,数据就被取走了
    2. 管道是半双工,可以用两个管道实现全双工。
      • 半双工,同一时间只能单向通信
      • 全双工,同一时间可以双向通讯
      • 单工,只能单向通讯
  12. I/O复用

    1. int select(int maxfd, fdset readset, fd_set _ writes, fd_set _ exceptset, const struct timeval _ timeout)
      1. maxed最大的检测数量,一般会多1,因为fd是从0开始
      2. readset检测待读取数据位
      3. writes检测可传输无阻塞数据位
      4. exceptset检测发生异常位
      5. timeout超时的设置位
        • sec秒 seconds
        • usec毫秒 microseconds
      6. 超时返回0,失败返回-1,其他数字就是剩下的文件描述符总数。
  13. 多种I/O函数

    1. 1
      
      ssize_t send(int sockfd, const void *buf, size_t len, int flags)
      
      • sockfd 套接字描述符
      • buf 缓存
      • len 待传输字节数
      • flags 标注位
        • 一般用0, 就和write()一样
    2. 1
      
      ssize_t recv(int sockfd, void *buf, size_t len, int flags)
      
      • sockfd 套接字描述符
      • buf 缓存
      • len 最大传输字节数
      • flags 标注位
        • 一般用0, 就和write()一样
        • 用msg_peek的话是从管道中不拿走, peek一下
  14. 多播与广播

  15. 套接字与标准I/O

    1. 1
      2
      3
      
      FILE *fdopen(int fd, const char *mode)
      FILE *fopen(const char *pathname, const char *mode) //也可以用pathname字符串来输入
      //从fd文件描述符转成FILE * 指针
      
    2. 1
      2
      
      int fileno(FILE *stream)
      //从FILE * 指针转成fd文件描述符
      
    3. 1
      2
      3
      4
      5
      6
      7
      
      fgets(),fputs()函数有缓存
      char *fgets(char *s, int size, FILE *stream)
      //读取
      int fputs(const char *s, FILE *stream)
      //输出字符串
      int fflush(FILE *stream)
      //刷新缓存, 把数据发送出去.
      
  16. 关于I/O流分离的其他内容

    1. 分离流可以让代码更好看,逻辑上更清晰
    2. 一般读用一个FILE指针, 写用一个FILE指针
    3. 如果这两个指针指向的都是一个文件描述符, 那么关闭( close() )其中一个FILE, 文件描述符也关了
    4. 所以解决这个问题, 要复制( dup() )一个文件描述符, 用2个FILE指针指向2个文件描述符,
      • 这样关闭其中写FILE指针, 读FILE指针也可以继续读
  17. 优于select的epoll

    1. select是条件触发

    2. epoll默认是条件触发,可以在epoll_ctl()更改event来变成边缘触发

      • event.events = EPOLLIN | EPOLLET
      • EPOLLIN是传入参数, 有需要读的情况的数值
      • 或运算EPOLLET后, 就变成了边缘触发
        • ET(Edge Triggered)边缘触发
        • LT(Level Triggered)水平触发
    3. epoll函数

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      
      int epoll_create(int size)
        //创建红黑树, 返回红黑树根结点
      int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
        //op是操作:  EPOLL_CTL_ADD, EPOLL_CTL_ADEL, EPOLL_CTL_MOD
        //fd: 操作的文件描述符
        //event:  要加入的事件
      int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
        //events传出参数
        //maxevents最大穿出数量
        //timeout 毫秒为单位, -1一直阻塞, 0不阻塞
      
    4. epoll标准函数过程

      1. 创建红黑树
      2. 用epoll_ctl添加 创建的accept()句柄
      3. 用epoll_wait返回的结果
      4. 根据fd判断是accept()还是接收客户端要发送
    5. epoll反应堆过程

      1. 创建红黑树
      2. 创建拥有同样多时间的结构体,或者函数,这些函数或结构体要放在data.*ptr上, 以便于返回后根据ptr找到函数或结构体
      3. 用epoll_ctl添加 ptr是accept()函数的 事件
      4. 封装的accept()的函数, 中能添加处理ptr赋值的事件
      5. 用epoll_wait返回的结果调用ptr函数
  18. 多线程服务器的实现

    1. 创建线程
    2. 线程同步
      1. 信号量
      2. 互斥量
  19. 制作http服务器端

    1. 请求消息(Request Message)

      1
      2
      3
      4
      5
      6
      7
      
      GET /indext.html HTTP/1.1
      User-Agent: Mozilla/5.0
      Accept: image/git, image/jpeg
      Accept-Language: zh-cn, zh;
      Accept-Encoding:gzip
      
      <消息体>只有POST方法才存在
      
      • 请求行
      • 消息头
      • 空行
      • 消息体
    2. 响应消息(Response Message)

      1
      2
      3
      4
      5
      6
      7
      
      HTTP/1.1 200 OK
      Server: SimpleWebServer
      Content-type: text/html;charset=gb2312
      Content-length: 2048
      
      <html>
      </html>
      
      • 状态行
      • 消息头
      • 空行
      • 消息体
  20. 总结(进阶内容)

    1. UNIX环境高级编程(第3版)
    2. TCP/IP详解 (卷1~卷3)
      1. 推荐卷1, 讲解的是TCP/IP协议
使用 Hugo 构建
主题 StackJimmy 设计