• Linux——网络编程总结性学习


    什么是ISP

    网络业务提供商_百度百科

    计算机网络有哪些分类方式,计算机网络有哪些分类?_陈泽杜的博客-CSDN博客

    路由器_百度百科

     目前实际的网络分层是TCP/IP四层协议

    当我们浏览⽹站找到想要下载的⽂件以后,找到相应的接⼝点击下载就好了。剩下的⼯作就交给⽹ 络了,那么⽹络是如果传输的呢?

            答案就是先封包然后再拆包。实际的远距离传输,可能会涉及多个⽹络,多个路由器。这⾥简化成 ⼀个来表示。我们看到,每⼀层都有相应的控制信息,需要加到数据前⾯,我们把这些控制信息称之为 包头。每层都有不同我包头,⽐如应⽤层可能就是FTP的包头,然后,传输层可能就是TCP包头,再往下 传输层: 应⽤层: 数据的封包与拆包 7 依次就是IP包,以太⽹ (Ethernet),到了物理层以后,上层交下来的数据,就会变成bit流,被放的实 际的物理设备上进⾏传输。

            如果⽬标在本⽹络内部,数据就会被直接发送的⽬标主机上⾯,作相反的操作,也就是拆包。⼀般 我们下载的⽂件基本上都存在于远程的服务器。所以,必然要经过多个⽹络,多个路由器。每个路由器 都按照如图所示的步骤,层层拆包,折到⽹络层的IP头以后,和⾃⼰的⼀个叫做路由表的东⻄进⾏⽐ 对,确定⼀个合适的⽹络地址,按照新的⽹络地址再次进⾏封装。下⼀个路由器⽣复这个动作,直到把 数据传送给⽬标主机为⽌。

            最后,再由⽬标主机,也就是你的电脑,进⾏拆包。然后把数据展示给你或者直接存储到磁盘上。

    网络程序的架构

    ⽹络程序通常有两种架构,⼀种是

    B/S(Browser/Server,浏览器/服务器)架构

    ⽐如我们使⽤⽕狐浏览器浏览Web⽹站,⽕狐浏览器就是⼀个Browser,⽹站上运⾏的Web就是⼀个服 务器。这种架构的优点是⽤户只需要在⾃⼰电脑上安装⼀个⽹⻚浏览器就可以了,主要⼯作逻辑都在服 务器上完成,减轻了⽤户端的升级和维护的⼯作量

    另外⼀种架构是C/S(Client/Server,客户机/服务器)架构

    这种架构要在服务器端和客户端分部安装不同的软件,并且不同的应⽤,客户端也要安装不同的客户机 软件,有时候客户端的软件安装或升级⽐较复杂,维护起来成本较⼤。但此种架构的优点是可以较充分 地利⽤两端的硬件能⼒,较为合理地分配任务。值得注意的是,客户机和服务器实际指两个不同的进 程,服务器是提供服务的进程,客户机是请求服务和接受服务的进程,它们通常位于不同的主机上(也 可以是同⼀主机上的两个进程),这些主机有⽹络连接,服务器端提供服务并对来⾃客户端进程的请求 做出响应。⽐如我们常⽤的QQ,我们⾃⼰电脑上的QQ程序就是⼀个客户端,⽽在腾讯公司内部还有服 务器端器程序。

    基于套接字的⽹络编程中,通常使⽤C/S架构。⼀个简单的客户机和服务器之间的通信过程如下: 1. 客户机向服务器提出⼀个请求

    2. 服务器收到客户机的请求,进⾏分析处理

    3. 服务器将处理的结果返回给客户机 通常,⼀个服务器可以向多个客户机提供服务。因此对服务器来说,还需要考虑如何有效地处理多个客 户机的请求。 

     这里的ip是公网ip,局域网也一样,在一个局域网内IP也不能相同,他们经过一个路由统一封装成公网ip。

     网络桥接_百度百科

    从前192.168是专用局域网段

     

     一般不使用的特殊ip

     

    IP地址是分等级的地址结构,分两个等级的好处是

     (3) 地址掩码 ⼜称为⼦⽹掩码 (subnet mask)。

    位数:32 位。

    ⽬的:让机器从 IP 地址迅速算出⽹络地址。

    由⼀连串 1 和接着的⼀连串 0 组成,⽽ 1 的个数就是⽹络前缀的⻓度。

    /20 地址块的地址掩码:11111111 11111111 11110000 00000000

    点分⼗进制记法:255.255.240.0

    CIDR 记法:255.255.240.0/20。

    默认地址掩码

     

     IP地址在Linux当中的实现

     IP地址是⼀个32位的数据

    通常被封装成如下数据类型

    struct in_addr { uint32_t s_addr; };

    in_addr_t

    uint32_t

     

     

     常用的熟知端口

     

    计算机电路先处理低位字节,效率比较高,因为计算都是从低位开始的。所以,计算机的内部处理都是小端字节序。但是,人类还是习惯读写大端字节序。所以,除了计算机的内部处理,其他的场合比如网络传输和文件储存,几乎都是用的大端字节序。正是因为这些原因才有了字节序。

    计算机处理字节序的时候,如果是大端字节序,先读到的就是高位字节,后读到的就是低位字节。小端字节序则正好相反

    1. #include
    2. typedef unsigned char byte;
    3. typedef unsigned int word;
    4. //#define N 1
    5. int main(int argc, char *argv[])
    6. {
    7. word val32 = 0x11223344;
    8. byte val8 = *( (byte*)&val32 );
    9. if(val8 == 0x44)
    10. printf("本机是⼩端字节序\n");
    11. else
    12. printf("本机是⼤端字节序\n");
    13. int c = 1;
    14. //int *a = c;
    15. char b = *(char*)&c;
    16. printf("%p %d\n",&c ,b);
    17. return 0;
    18. }

     

    1. #include
    2. #include
    3. typedef unsigned char byte;
    4. typedef unsigned int word;
    5. int main(int argc, char *argv[])
    6. {
    7. word val32 = 0x11223344;
    8. byte val8 = *( (byte*)&val32 );
    9. if(val8 == 0x44)
    10. {
    11. printf("本机是⼩端字节序\n");
    12. val32 = htonl(val32);
    13. val8 = *( (byte*)&val32 );
    14. if(val8 == 0x44)
    15. printf("字节序没有转换\n");
    16. else
    17. printf("转换成功, 现在是⽹络字节序了\n");
    18. }
    19. return 0;
    20. }

     IP地址的转换函数

     

    来个小实验,使用本机的两个虚拟机根据ip和端口号通信

     

    只能一对一谁手快和谁通信

     服务器是如何实现每台服务器都是公网IP的呢?

    socket分类

     

     

     

    流式套接字对应TCP数据报套接字对应UDP,所以protocol是0,只用用原始套接字时才需要有参数。

     套接字不知用于网络通信也可用于进程间通信,在网络通信中可选用IIPV4和IPV6

     

     

    !g就是shell中上次输入的g开头的命令

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. int main(int argc, char **argv)
    7. {
    8. int fd = socket(AF_INET, SOCK_STREAM, 0);
    9. if(fd < 0)
    10. {
    11. perror("socket");
    12. exit(0);
    13. }
    14. struct sockaddr_in addr;
    15. addr.sin_family = AF_INET;
    16. addr.sin_port = htons(8888);
    17. addr.sin_addr.s_addr = inet_addr("192.168.26.128");
    18. if(bind(fd, (struct sockaddr *)&addr, sizeof(addr)))//成功0/失败-1
    19. {
    20. perror("bind");
    21. exit(0);
    22. }
    23. struct sockaddr_in sin;
    24. socklen_t sinlen = sizeof(addr);
    25. if(getsockname(fd, (struct sockaddr *)&sin, &sinlen))
    26. {
    27. perror("getsockname");
    28. exit(0);
    29. }
    30. printf("文件描述符%d绑定地址是%s,端口号%d\n", fd, inet_ntoa(sin.sin_addr),ntohs(sin.sin_port));
    31. return 0;
    32. }

     

     

     

     

     

     

     

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #define BACKLOG 5//可以有5个等待在队列中
    8. int main(int argc, char **argv)
    9. {
    10. int fd = socket(AF_INET, SOCK_STREAM, 0);
    11. if(fd < 0)
    12. {
    13. perror("socket");
    14. exit(0);
    15. }
    16. struct sockaddr_in addr;
    17. addr.sin_family = AF_INET;
    18. addr.sin_port = htons(8888);
    19. addr.sin_addr.s_addr = inet_addr("192.168.26.128");
    20. if(bind(fd, (struct sockaddr *)&addr, sizeof(addr)))//成功0/失败-1
    21. {
    22. perror("bind");
    23. exit(0);
    24. }
    25. struct sockaddr_in sin;
    26. socklen_t sinlen = sizeof(addr);
    27. if(getsockname(fd, (struct sockaddr *)&sin, &sinlen))
    28. {
    29. perror("getsockname");
    30. exit(0);
    31. }
    32. printf("文件描述符%d绑定地址是%s,端口号%d\n", fd, inet_ntoa(sin.sin_addr),ntohs(sin.sin_port));
    33. if(listen(fd, BACKLOG)){
    34. perror("listen");
    35. exit(0);
    36. }
    37. printf("listen...\n");
    38. struct sockaddr_in cin;
    39. socklen_t cinlen = sizeof(cin);
    40. int newfd = accept(fd, (struct sockaddr *)&cin, &cinlen);
    41. //int newfd = accept(fd, NULL, NULL);
    42. if(newfd < 0)
    43. {
    44. perror("accept");
    45. exit(0);
    46. }
    47. printf("文件描述符%d绑定IP地址%s,端口号%d\n", newfd, inet_ntoa(cin.sin_addr), ntohs(cin.sin_port));
    48. char buf[1024] = {};
    49. read(newfd, buf, 1024);
    50. printf("%s\n", buf);
    51. close(newfd);
    52. close(fd);
    53. return 0;
    54. }

     还是用nc这次可以看连接服务器用户的相关信息

     

     

     

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. int main(int argc, char *argv[])
    11. {
    12. if(argc != 3)
    13. {
    14. printf("%s [IP][PORT]\n", argv[0]);
    15. exit(0);
    16. }
    17. /*1.创建套接字*/
    18. int fd = socket(AF_INET, SOCK_STREAM, 0);
    19. if(fd < 0)
    20. {
    21. perror("socket");
    22. exit(0);
    23. }
    24. /*2.设置通信结构体*/
    25. struct sockaddr_in sin;
    26. sin.sin_family = AF_INET;
    27. sin.sin_port = htons(atoi(argv[2]));
    28. sin.sin_addr.s_addr = inet_addr(argv[1]);
    29. /*3.向服务端发起连接请求*/
    30. if(connect(fd, (struct sockaddr *)&sin, sizeof(sin)))
    31. {
    32. perror("connect");
    33. exit(0);
    34. }
    35. socklen_t sinlen = sizeof(sin);
    36. if(getsockname(fd, (struct sockaddr *)&sin, &sinlen))
    37. {
    38. perror("getsockname");
    39. exit(0);
    40. }
    41. printf("文件描述符%d绑定IP地址%s,端口号%d\n", fd, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
    42. /*4.通信*/
    43. char buf[1024] = {"test\n"}; //8142
    44. write(fd, buf, strlen(buf)+1);
    45. memset(buf, 0, 1024);
    46. //printf("input->");
    47. //fgets(buf, , stdin);
    48. //write(fd, buf, strlen(buf)+1);
    49. read(fd, buf, 1024);
    50. printf("buf = %s\n", buf);
    51. close(fd);
    52. return 0;
    53. }
    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #define BACKLOG 5//可以有5个等待在队列中
    8. int main(int argc, char *argv[])
    9. {
    10. if(argc != 3)
    11. {
    12. fprintf(stderr, "%s [IP] [PORT] \n", argv[0]);
    13. exit(0);
    14. }
    15. int fd = socket(AF_INET, SOCK_STREAM, 0);
    16. if(fd < 0)
    17. {
    18. perror("socket");
    19. exit(0);
    20. }
    21. struct sockaddr_in addr;
    22. addr.sin_family = AF_INET;
    23. addr.sin_port = htons(atoi(argv[2]));
    24. addr.sin_addr.s_addr = inet_addr(argv[1]);
    25. if(bind(fd, (struct sockaddr *)&addr, sizeof(addr)))//成功0/失败-1
    26. {
    27. perror("bind");
    28. exit(0);
    29. }
    30. struct sockaddr_in sin;
    31. socklen_t sinlen = sizeof(addr);
    32. if(getsockname(fd, (struct sockaddr *)&sin, &sinlen))
    33. {
    34. perror("getsockname");
    35. exit(0);
    36. }
    37. printf("文件描述符%d绑定地址是%s,端口号%d\n", fd, inet_ntoa(sin.sin_addr),ntohs(sin.sin_port));
    38. if(listen(fd, BACKLOG)){
    39. perror("listen");
    40. exit(0);
    41. }
    42. printf("listen...\n");
    43. struct sockaddr_in cin;
    44. socklen_t cinlen = sizeof(cin);
    45. int newfd = accept(fd, (struct sockaddr *)&cin, &cinlen);
    46. //int newfd = accept(fd, NULL, NULL);
    47. if(newfd < 0)
    48. {
    49. perror("accept");
    50. exit(0);
    51. }
    52. printf("文件描述符%d绑定IP地址%s,端口号%d\n", newfd, inet_ntoa(cin.sin_addr), ntohs(cin.sin_port));
    53. char buf[1024] = {};
    54. read(newfd, buf, 1024);
    55. printf("%s\n", buf);
    56. close(newfd);
    57. close(fd);
    58. return 0;
    59. }

     

     

     哈哈天天ping百度百度不爱搭理了,ping一下华清试试 

    socket有两个缓冲区一个发送一个接收

     

     

    1. #include "net.h"
    2. int main(int argc, char *argv[])
    3. {
    4. if(argc != 3)
    5. {
    6. printf("%s [IP][PORT]\n", argv[0]);
    7. exit(0);
    8. }
    9. /*1.创建套接字*/
    10. int fd = socket(AF_INET, SOCK_DGRAM, 0);
    11. if(fd < 0)
    12. {
    13. perror("socket");
    14. exit(0);
    15. }
    16. /*2.设置通信结构体*/
    17. struct sockaddr_in sin;
    18. sin.sin_family = AF_INET;
    19. sin.sin_port = htons(atoi(argv[2]));
    20. sin.sin_addr.s_addr = inet_addr(argv[1]);
    21. /*3.向服务端发起连接请求*/
    22. if(connect(fd, (struct sockaddr *)&sin, sizeof(sin)))
    23. {
    24. perror("connect");
    25. exit(0);
    26. }
    27. /*4.通信*/
    28. char buf[BUFSIZ];
    29. while(1)
    30. {
    31. bzero(buf, BUFSIZ);
    32. printf("input->");
    33. fgets(buf, BUFSIZ, stdin);
    34. send(fd, buf, strlen(buf)+1, 0);
    35. printf("buf = %s\n", buf);
    36. if(buf[0] == '#')
    37. break;
    38. }
    39. close(fd);
    40. return 0;
    41. }

     

     

     

    相关程序参考Linux——UDP_宇努力学习的博客-CSDN博客 

    先win+R wt 然后telnet 

    win上没有nc可以用telnet

     

     

     看以往文章

    这里记录一个老师写的大型群体交流服务器

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #define BACKLOG 5
    10. void handle(int sig)
    11. {
    12. printf("child process exit...\n");
    13. wait(NULL);
    14. }
    15. int main(int argc, char *argv[])
    16. {
    17. if(argc != 3)
    18. {
    19. printf("%s[IP][PORT]\n", argv[0]);
    20. exit(0);
    21. }
    22. signal(SIGCHLD, handle);
    23. int fd = socket(AF_INET, SOCK_STREAM, 0);
    24. if(fd < 0)
    25. {
    26. perror("socket");
    27. exit(0);
    28. }
    29. struct sockaddr_in addr;
    30. addr.sin_family = AF_INET;
    31. addr.sin_port = htons(atoi(argv[2]));
    32. addr.sin_addr.s_addr = inet_addr(argv[1]);
    33. if( bind(fd, (struct sockaddr *)&addr, sizeof(addr)) )
    34. {
    35. perror("bind");
    36. exit(0);
    37. }
    38. struct sockaddr_in sin;
    39. socklen_t sinlen = sizeof(addr);
    40. if(getsockname(fd, (struct sockaddr *)&sin, &sinlen))
    41. {
    42. perror("getsockname");
    43. exit(0);
    44. }
    45. printf("文件描述符%d绑定的IP地址是%s,端口号%d\n", fd, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
    46. if( listen(fd, BACKLOG) )
    47. {
    48. perror("listen");
    49. exit(0);
    50. }
    51. printf("listen...\n");
    52. pid_t pid;
    53. int newfd;
    54. char buf[1024] = {};
    55. struct sockaddr_in cin;
    56. socklen_t cinlen = sizeof(cin);
    57. while(1)
    58. {
    59. newfd = accept(fd, (struct sockaddr *)&cin, &cinlen);
    60. if(newfd < 0)
    61. {
    62. perror("accept");
    63. exit(0);
    64. }
    65. printf("文件描述符%d绑定的IP地址是%s,端口号%d\n", newfd, inet_ntoa(cin.sin_addr), ntohs(cin.sin_port));
    66. pid = fork();
    67. if(pid < 0)
    68. {
    69. perror("fork");
    70. exit(0);
    71. }
    72. else if(!pid)
    73. {
    74. close(fd);
    75. while(1)
    76. {
    77. memset(buf, 0, 1024);
    78. if(!read(newfd, buf, 1024))
    79. break;
    80. printf("%s\n", buf);
    81. }
    82. close(newfd);
    83. exit(0);
    84. }
    85. else
    86. close(newfd);
    87. }
    88. close(fd);
    89. return 0;
    90. }

    select实现服务器

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. typedef struct sockaddr Addr;
    11. typedef struct sockaddr_in Addr_in;
    12. typedef struct Node{
    13. int fd;
    14. struct Node *next;
    15. }Node;
    16. #define BACKLOG 5
    17. void Argment(int argc, char *argv[]);
    18. void NodeCreate(Node **p);
    19. void AcceptHandle(int sfd, Node **H);
    20. int ClientHandle(int fd);
    21. int main(int argc, char *argv[])
    22. {
    23. int ret, sfd, nfd = 0;
    24. Addr_in saddr;
    25. fd_set rfds;
    26. Node *H, *p = NULL;
    27. Argment(argc, argv);
    28. NodeCreate(&H);
    29. sfd = socket(AF_INET, SOCK_STREAM, 0);
    30. if(sfd < 0)
    31. {
    32. perror("socket");
    33. exit(0);
    34. }
    35. saddr.sin_family = AF_INET;
    36. saddr.sin_port = htons(atoi(argv[2]));
    37. saddr.sin_addr.s_addr = inet_addr(argv[1]);
    38. if(bind(sfd, (Addr *)&saddr, sizeof(Addr_in)))
    39. {
    40. perror("bind");
    41. exit(0);
    42. }
    43. if(listen(sfd, BACKLOG))
    44. {
    45. perror("listen");
    46. exit(0);
    47. }
    48. H->fd =sfd;
    49. while(1)
    50. {
    51. FD_ZERO(&rfds);
    52. p = H;
    53. nfd = 0;
    54. while(p != NULL)
    55. {
    56. if(p->fd > nfd)
    57. nfd = p->fd;
    58. FD_SET(p->fd, &rfds);
    59. p = p->next;
    60. }
    61. printf("nfd = %d run select...\n", nfd);
    62. ret =select(nfd+1, &rfds, NULL, NULL, NULL);
    63. if(!ret)
    64. continue;
    65. if(ret < 0)
    66. {
    67. perror("select");
    68. exit(0);
    69. }
    70. p = H;
    71. while(p->next != NULL)
    72. {
    73. if(FD_ISSET(p->fd, &rfds))
    74. {
    75. if(ClientHandle(p->fd) <= 0)
    76. {
    77. close(p->fd);
    78. Node *q = p->next;
    79. p->fd = q->fd;
    80. p->next = q->next;
    81. free(q);
    82. continue;
    83. }
    84. }
    85. p = p->next;
    86. }
    87. if(FD_ISSET(p->fd, &rfds))
    88. AcceptHandle(p->fd, &H);
    89. #if 1
    90. p = H;
    91. puts("");
    92. printf("Node:");
    93. while(p != NULL)
    94. {
    95. printf("%d ", p->fd);
    96. p = p->next;
    97. }
    98. #endif
    99. if(H->next == NULL)
    100. break;
    101. }
    102. close(sfd);
    103. free(H);
    104. return 0;
    105. }
    106. void Argment(int argc, char *argv[])
    107. {
    108. if(argc != 3)
    109. {
    110. fprintf(stderr, "%s [addr] [port]\n", argv[0]);
    111. exit(0);
    112. }
    113. }
    114. void NodeCreate(Node **p)
    115. {
    116. *p = malloc(sizeof(Node));
    117. if(p == NULL)
    118. {
    119. perror("malloc");
    120. exit(0);
    121. }
    122. bzero(*p, sizeof(Node));
    123. }
    124. void AcceptHandle(int sfd, Node **H)
    125. {
    126. Node *p = NULL;
    127. Addr_in caddr;
    128. socklen_t caddr_len = sizeof(Addr_in);
    129. int cfd = accept(sfd, (Addr *)&caddr, &caddr_len);
    130. if(cfd < 0)
    131. {
    132. perror("accept");
    133. exit(0);
    134. }
    135. fprintf(stderr, "client %s:%d connect success.\n",
    136. inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));
    137. NodeCreate(&p);
    138. p->fd = cfd;
    139. p->next = *H;
    140. *H = p;
    141. }
    142. int ClientHandle(int fd)
    143. {
    144. int ret;
    145. char buf[1024] = {};
    146. ret = recv(fd, buf, 1024, 0);
    147. if(ret <= 0)
    148. return 0;
    149. printf("fd=%d buf = %s\n",fd, buf);
    150. if(buf[0] == '#')
    151. return 0;
    152. return ret;
    153. }

  • 相关阅读:
    STM32物联网项目-HMI串口屏
    如何实现 Python Switch Case 语句?
    FPGA实现双向电平转换
    C#可视化 家用轿车信息查询系统(具体做法及全部代码)
    scp 出现Permission denied错误 解决方法
    Hystrix的原理及应用:构建微服务容错体系的利器(一)
    (2022牛客多校五)B-Watches(二分)
    Mysql的JDBC知识点
    《Python数据分析入门学习》- 3、进阶数据预处理
    Redis基础
  • 原文地址:https://blog.csdn.net/qq_52479948/article/details/127971032