网络笔记

网络:

1. OSI模型?

    * 物理层:硬件连接的接口。

    * 数据链路层: 通信道的无差错传输,提供数据成帧。

    * 网络层: 将数据正确并且迅速的从原点主机传送到目的主机。

    * 传输层: 掩盖下层结构细节,保证会话层的消息正确的传输到另一方的会话层。

    * 会话层: 实现两端主机之间的会话管理。

    * 表示层: 信息转换,压缩,解密,代码转换。

    * 应用层: 提供日常的应用。

2. 网络?

网络连接也是一个文件,它也有文件描述符!

stdin:0 标准输入

stdout:1 标准输出

数据传送不会消失,顺序传送,发送和接收非同步。

TCP/IP

TCP:保证数据的可靠性,和正确性。

IP:控制数据如何从源头到达目的地。

3. 进程?

  正在执行的程序被称为进程,进程树顶端是init控制进程。

* fork() 调用进程创建新的进程。

* wait() 进程同步措施,使一个进程等待进程,到另一个进程结束为止。

* exit() 终止一个进程的运行。

* exec() 系统调用。

pid_t fork(void); // 创建一个进程,返回进程id是pid_t类型。

4. TCP和UDP?

tcp:可靠的通信传输,面向连接,面向字节流,数据传输慢。

udp:不需要建立连接,不可靠通信传输,面向报文,速度快。

5. 常见端口及对应服务?

21    FTP文件传输协议

22    SSH

23    Telnet

80    HTTP超文本传输协议

6379  redis默认端口

6. tcp三次握手?

  * 客户端发送请求SYN报文段到服务器,进入SYN_SEND状态,等待服务器确认。      发送 SYN=1 seq=client_isn

  * 服务器收到SYN进行确认,回复给客户端,进入SYN_RECV状态。                 发送 SYN=1 seq=server_isn  ack=client_isn+1

  * 客户端收到SYN_ACK报文段,进入ESTABLISHED状态,完成三次握手。            发送 SYN=0 seq=clien_isn+1 ack=server_isn+1

7. tcp四次挥手?

  * 客户端发送连接释放报文,停止发送数据,进入终止等待状态 1                 发送 FIN=1 seq=client_isn                

  * 服务器收到报文,发出确认报文ack带上自己序列号seq,进入等待关闭状态       发送  ack=client_isn+1  seq=server_isn

    * 客户端收到服务器报文后,进入终止等待状态 2

  * 服务器发送完数据后,向客户端发送释放报文,自身进入最后确认状态。          发送 FIN=1 ack=client_isn+1 seq=server_isn

  * 客户端收到确认后,发送最后确认,进入wait状态,等待2*MSL时间。            发送 ack=server_isn+1 seq=client_isn+1

    * 服务器收到客户端发出的确认,立即进入close状态。

8. 为什么结束连接的TIME_WAIT需要等待2MSL才能返回close状态?

客户端发送的最后一步的确认,不完全是可靠的,网络可能存在别的异常情况。

所以客户端会进入TIME_WAIT状态,设置定时器,如果服务器一直发送第三步消息,client会再次发送确认信息,并继续等待2MSL时间。

2MSL:网络的最大存活时间,一个发送和一个回复所需的最大时间。

直到服务器收到最后确认,不再发送FIN消息,就知道已经被成功接收,结束tcp连接。

9. 建立了连接,客户端故障。

tcp存在保活计时器。 服务器在既定时间(2h)没有收到客户端的任何消息。然后每隔一段时间(75s)发送一个探测报文段。

如果一连10次都没有反应,将自动关闭这个连接。

10. IP地址分类。

A   1.0.0.1 - 127.255.255.254

B   128.0.0.1 - 191.255.255.254

C   192.0.0.1 - 223.255.255.254

D   224.0.0.0 - 239.255.255.255

E   保留用于实验使用

11. tcp比udp慢的原因?

* 收发数据前后进行的连接设置及清除过程。

* 收发过程中为保证数据可靠性添加的流控制。

12. udp的传输函数:

ssize_t sendto(int sock, void *buff, size_t nbytes, int flags, struct sockaddr *to, socklen_t addrlen);

sock: 创建的套接字

buff: 传输数据的缓冲地址值。

nbytes: 待传输的字节数据

flags: 可选项参数,无则是0

to: 发送对象地址。

addrlen:地址结构体长度

13. udp的接收函数?

ssize_t recvfrom(int sock, void *buff, size_t nbytes, int flags, struct sockaddr* from, socklen_t addrlen);

和上面基本信息一样。

14:udp

不存在请求和连接,因此某种意义上说,不区分服务器和客户端。

15:回声消息,read和write

tcp在发送数据时候,如果数据过大,会分包发送,如果write和read是同时进行的,那么会存在,write还没有把数据全部发送到服务器,

服务器回复一部分数据时,read读取会出现问题。

16. 什么是协议?

网络中交换数据的标准规则,约定的集合。

17. 大端小端?

大端:高位字节存放到低位地址。

小端:高位字节存放到高位地址。

* 程序判断:int i = 0x12345678 char *c = (char *)&i; c[0] == 0x12 小端

* typedef union {

*   int i;

*   char c;

* } myunion;

* myunion.i = 1; return myunion.i == myunion.c

18. tcp和udp的4层协议栈?经过的层级结构差异

应用层, tcp/udp层,IP层,链路层。

19. write和read函数。

write和read交互,write可以直接一次性将数据发送到另一端,但是read不一定能全部读取,因为数据量太大的情况下,read读不全数据。

20. udp

tcp在不可靠的IP层进行流控制,udp缺少这种流控制。

tcp和udp最基本的区别就是流控制,其它区别所剩无几。

21. 压缩文件传输。

压缩文件必须选择tcp进行传输,如果中途有数据丢失,解压就会失败,所以必须是选择tcp进行传输。

22. gethostbyname 通过域名转换为IP

struct hostent{

  char *h_name;        // office name 官方域名

  char **h_aliases;    // alias list 同一IP可以绑定多个域名,出官方域名,还有其它域名。

  int h_addrtype;      // IP地址族信息,

  int h_length;        //

  char **h_addr_list;  // IP

}

23. Nagle算法。tcp 消息。

只有收到前一数据的ACK消息时,Nagle算法才发送下一次数据。

开启Nagle算法时候,会合理的减少流量,但是传输速度会降低。

关闭Nagle算法时候,会增加网络流量,传输速度会增加,尤其是在大数据量的传输中,这种速度会很明显。

注:未准确判断数据特性时不应禁用Nagle算法。

禁用Nagle算法: int opt_val = 1

开启Nagle算法: int opt_val = 0

setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&opt_val, sizeof(opt_val))

24. 并发服务器的实现。

多进程服务器: 通过创建多个进程提供服务。

多路复用服务器: 通过捆绑并统一管理I/O对象提供服务。

多线程服务器: 通过生成与客户端等量的线程提供服务。

25. 进程和子进程

fork创建进程之后,父进程返回子进程的进程ID

子进程返回0.

父子进程,只共享一段代码,有不同的数据存储空间。

26. 僵尸进程

子进程比父进程先结束,父进程又没有回收子进程,释放子进程占用的资源。

应向创建子进程的父进程传递子进程的exit参数或return返回。

* 只有父进程主动发起请求,操作系统才会传递该值。(父母要负责回收自己孩子。)

27. wait函数

调用wait函数可以将终止的子进程退出。wait函数会阻塞等待,直到有子进程退出。

WIFEXITED 子进程正常终止时返回 true

WEXITSTATUS 返回子进程的返回值

28. waitpid函数

wait函数会引起程序阻塞。waitpid(pid_t, pid, int * statloc, int options);成功返回终止的子进程ID,失败返回-1

参数: pid 等待目标子进程,若为-1,则可以等待任意子进程退出。

statloc: status  options: WNOHANG即使没有终止的子进程,也不会进入阻塞状态。

29. 信号。

void (*signal(int signo, void(*func)(int)))(int);

void function(int flag) {}

调用signal signal(SIGNO, function)

接收第二个参数是一个函数指针(地址),函数的参数是int类型,返回值是void

30.  信号的高级用法:

  struct sigaction act;

  act.sa_handler = read_childproc;  

  sigemptyset(&act.sa_mask);  

  act.sa_flags = 0;     

  sigaction(SIGCHLD,&act,0);  //注册信号,触发SIGCHILD信号后将会调用act函数

  return 和 exit将会触发到该信号。

  read_childproc函数如下:

  void read_childproc(int sig){  

      int status;  


      pid_t id = waitpid(-1, &status, WNOHANG);  


      if(WIFEXITED(status)){  

        printf("Removed proc id : %d \n",id);  

        printf("child send : %d \n",WEXITSTATUS(status));  

      }   

  }

31. 进程间通信->pipe

int pipe(int fileds[2]) fileds[0] 出口, fileds[1] 入口

test:

  int fds[2]; pipe(fds); fork一个父进程,和子进程,子进程写数据到文件,父进程从文件读数据,就实现了进程间通信、

32. fread和read

fread是C语言的库,read是系统调用。

 read每次读取要求大小的数据,从用户态切换到内核态(损耗性能)

 fread每次从内核缓冲区读取较多的数据,放到应用进程缓冲区,下次再取直接去应用进程缓冲区取,不用消耗太多性能。

 33. fwrite和write

 write是系统调用,每次需要将数据写到磁盘,写的大小是要求的大小,依然涉及频繁的用户态和内核态切换。

 fwrite是库函数,每次讲数据写入到换乘区,等缓冲区满了,一次写入磁盘。或者使用fflush冲洗缓冲区。

 34. sigaction 捕捉信号的类型

      struct sigaction {

          void (*sa_handler)(int);  // 信号处理函数

          void (*sa_sigaction)(int, siginfo_t *, void *);

          sigset_t sa_mask;         // 设置处理该信号时,暂时将sa_mask指定信号搁置

          int sa_flags;             // 信号其它相关操作。

          void (*sa_restorer)(void);  // 

      }

  注:联合 信号的高级用法使用

35. 使用多任务并发服务器

  fork出来的子进程,需要关闭ser_sockID 只保留父进程的ser_sockID,持续去accept客户端的连接。

  父进程,只负责接收客户端的连接,客户端的cli_sockID 也需要关闭。

36. I/O复用.

  select 将多个文件描述符,集中到一起进行监控。

  fd_set set; FD_ZERO, 清零。 FD_SET 设置1, FD_CLR 单个清零。

37. select函数

int select(int maxfd, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct 

timeval *timeout)

调用select函数后,除了发生变化的描述符外,剩下的所有位都将被初始化为0。

38. select使用。

在进行select使用时候,需要维护两个描述符集合(use,copy),两个内容一样。

复制的copy,用作select调用传入,当有收到消息时候,copy内除了有消息的描述符,其它都被置0。

所以只需要循环检查,FD_ISSET 文件描述符是否存在copy中,如果存在,就证明这个有消息了。开始处理吧。

39. 多播(组播)、广播.

int so_ard = 1

广播: setsockopt(sockid, SOL_SOCKET, SOL_BORADCAST, (void *)&so_ard, sizeof(so_ard))

40. 标准IO的缺点

* 不容易进行双向通信

* 有时可能需要频繁的调用fflush

* 需要以FILE结构体指针的形式返回文件描述符

41. select的弊端

无论如何优化程序性能,也无法同时接入上百个客户端,select不适合以web服务器端。

42. select函数

每次调用select函数时,向操作系统传递检视对象信息。

仅向操作系统传递1次监视对象,监视的范围发生变化时,只通知发生变化的事项。

43. epoll的优点

无需编写以检视状态变化为目的的针对所有文件描述符的循环语句。

调用对于select函数的epoll_wait函数时,无需每次传递检视对象信息。

44. epoll需要的3个函数

epoll_create 创建保存epoll文件描述符的空间

epoll_ctl 想空间注册并注销文件描述符

epoll_wait 与select函数类似,等待文件描述符发生变化

45. select和epoll不同点

select需要FD_SET, FD_CLR函数。        epoll需要通过epoll_wait函数。

select下调用select函数等待描述符变化。 epoll中调用epoll_wait函数。

select下通过fd_set查看检视对象的变化。 epoll中通过结构体epoll_event将发生变化的文件描述符几种到一起。

struct epoll_event {

  __unit32_t events;

  epoll_data_t data;

}

46. epoll_create(int size)函数

epoll_create创建的文件描述符保存空间称为"epoll例程", 

参数size的值,决定epoll例程的大小。

47. epoll_ctl

生成epoll例程后,在内部注册监视对象文件描述符,使用epoll_ctl函数。

epoll_ctl(int epfd, int op, int fd, struct epoll_event * event)

op参数的模型如下 

 * EPOLL_CTL_ADD 注册到例程中

 * EPOLL_CTL_DEL 例程中删除文件描述符

 * EPOLL_CTL_MOD 更改文件描述符的关注事件发生情况

 48. epoll_wait

int epoll_wait(int fd, struct epoll_event* events, int maxevents, int timeout)

epfd: 发生监视范围的epoll

events: 保存发生事件的文件描述符集合的结构体地址值

maxevents: 第二个参数中保存最大的事件数

timeout:等待时间

epoll回声服务器端

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <sys/socket.h>

#include <sys/epoll.h>

#define BUFF_SIZE 100

#define EPOLL_SIZE 50

int main(int argc, char *argv[])

{

    int ser_sock, cln_sock;

    struct sockaddr_in ser_adr, cln_adr;

    socketlen_t adr_sz;

    int str_len, i;

    char buf[BUFF_SIZE];

    struct epoll_event *ep_events;

    struct epoll_event event;

    int epfd, event_cnt;

    ser_sock = socket(PF_INET, SOCK_STREAM, 0);

    memset(&ser_adr, 0, sizeof(ser_adr));

    ser_adr.sin_family = AF_INET;

    ser_adr.sin_addr.s_addr = htonl(INADDR_ANY);

    ser_adr.sin_port = htons(atoi(argv[1]));

    if(bind(ser_sock, (struct sockaddr*)&ser_adr, sizeof(ser_adr)) == -1)

      error();

    if(listen(ser_sock, 5) == -1)

      error();

    // 创建epoll的例程空间

    epfd = epoll_create(EPOLL_SIZE); // 返回值和套接字相同,最后也需要close掉

    ep_events = malloc(sizeof(struct epoll_event)*EPOLL_SIZE); // 申请一个epoll空间池

    event.events = EPOLLIN; // 需要读取数据情况

    event.data.fd = ser_sock; // socket的文件描述符

    epoll_ctl(epfd, EPOLL_CTL_ADD, ser_sock, &event); // 添加一个事件

    while(1)

    {

      // 返回发生事件的文件描述符数, event_cnt个数

      event_cnt = epoll_wait(epfd, ep_events, EPOLL_SIZE, -1); 

      if(event_cnt == -1)

        break;

      for(i=0; i<event_cnt; i++)

      {

        if(ep_events[i].data.fd == ser_sock) // 新的客户端连接走这里。

        {

          // 将新连接的客户端fd加入到epoll例程中

          adr_sz = sizeof(cln_adr);

          cln_sock = accept(ser_sock, (struct sockaddr*)&cln_adr, &adr_sz);

          event.events = EPOLLIN;

          event.data.fd = cln_sock;

          epoll_ctl(epfd, EPOLL_CTL_ADD, cln_sock, &event);

          printf("connected client: %d\n", cln_sock);

        }

        else

        {

          // 实现和已连接的客户端通信

          str_len = read(ep_events[i].data.fd, buf, BUFF_SIZE);

          if(str_len == 0)

          {

            // 处理完事件之后,将其从例程中删除。

            epoll_ctl(epfd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL);

            close(ep_events[i].data.fd);

            printf("close client:%d\n", ep_events[i].data.fd);

          }

          else

          {

            write(ep_events[i].data.fd, buf, str_len);

          }

        }

      }

    }

    close(ser_sock);

    close(epfd);

    return 0;

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351

推荐阅读更多精彩内容