Linux网络异常处理(6.12)

来源:互联网 发布:优质小麦基因组数据库 编辑:程序博客网 时间:2024/05/16 13:46
[1] 网络异常处理
    1. 客户端出了问题(死机、重启了、网络断了...)
    2. 服务端出了问题(死机、重启了、网络断了、内存耗尽、...)
    3. 网络不正常
    
    解决办法: 心跳包
    
    心跳包的实现方法:
    1. 利用TCP协议的KeepAlive(TCP协议实现的心跳包)
       见《tcp_keepalive》的服务端
       
    2. 设置接收超时检测心跳,对端需要定时发送
       heart_beat程序只在接收端实现了如何(利用阻塞超时)检测超时
       
    3. 如何实现应用程序的定时发送和超时检测?
       alarm
    
    总结: 利用实现心跳包
    
[2] 广播

    1. 接收端流程

//       (1) 创建套接字           sockfd = socket(AF_INET, SOCK_DGRAM, 0);           //       (2) 绑定IP和端口到socket           struct sockaddr_in addr;                      bzero(&addr, sizeof(addr));           addr.sin_family = AF_INET;           addr.sin_port = htons(port);           addr.sin_addr.s_addr = inet_addr(ip);           // addr.sin_addr.s_addr = INADDR_ANY;                      ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));           //       (3) 接收           struct sockaddr_in peer_addr;           socklen_t addrlen = sizeof(peer_addr);                      ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&peer_addr, &addrlen);           //       (3) 关闭           close(sockfd);  
    2. 发送端流程
//       (1) 创建套接字           sockfd = socket(AF_INET, SOCK_DGRAM, 0);           //       (2) 设置套接字,使能广播           int on = 1;                      ret = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));           if (-1 == set){                        }                      SOL_SOCKET:          //设置的选项在socket层           SO_BROADCAST:        //设置是否允许广播 0 - 不能 1-可以           //       (3) 通过广播地址发送广播           struct sockaddr_in broad_addr;                      bzero(&broad_addr, sizeof(broad_addr));           broad_addr.sin_family = AF_INET;           broad_addr.sin_port = htons(port);           broad_addr.sin_addr.s_addr = inet_addr//(一定填广播(192.168.0.255));                      ret = sendto(sockfd, buf, len, 0, (struct sockaddr *)&broad_addr, sizeof(broad_addr));           //       (4) 关闭           clos(sockfd);

[3] 组播        
    1. 分组
       每个D类IP地址就是一个组,组播实现原理:
       接收 -- 加入一个组
       发送 -- 向一个组(目标IP地址为组播地址)发送数据包  
       
    2. 组播地址(IP地址和网卡地址)
       IP地址: D类地址 ,高位固定为1110,范围: 224.0.0.0-239.255.255.255
       网卡地址: 前24bit固定为01-00-5e, 最后23bit是D类IP地址的后23bit直接映射下来 -- 仅仅正对于以太网
       
    3. 接收流程

//       (1) 创建套接字           sockfd = socket(AF_INET, SOCK_DGRAM, 0);           //       (2) 加入组           struct ip_mreq mreq;           mreq.imr_multiaddr.s_addr = inet_addr(argv[1]);  // "224.10.10.1"           mreq.imr_interface.s_addr = INADDR_ANY;                      ret = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));           //       (3) 绑定IP地址和端口           struct sockaddr_in addr;                      bzero(&addr, sizeof(addr));           addr.sin_family = AF_INET;           addr.sin_port = htons(port);           addr.sin_addr.s_addr = inet_addr(ip);           // addr.sin_addr.s_addr = INADDR_ANY;                      ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));           //       (4) 接收           struct sockaddr_in peer_addr;           socklen_t addrlen = sizeof(peer_addr);                      ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&peer_addr, &addrlen);           //       (3) 关闭           close(sockfd);
    4. 发送流程
//       (1) 创建套接字           sockfd = socket(AF_INET, SOCK_DGRAM, 0);           //       (2) 发送           struct sockaddr_in muticast_addr;                      bzero(&muticast_addr, sizeof(muticast_addr));           muticast_addr.sin_family = AF_INET;           muticast_addr.sin_port = htons(port);           muticast_addr.sin_addr.s_addr = inet_addr//(一定填多播(224.10.10.1));                      ret = sendto(sockfd, buf, len, 0, (struct sockaddr *)&broad_addr, sizeof(broad_addr));           //       (3) 关闭           close(sockfd);

send.c

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <string.h>#include <strings.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>// ./send 192.168.0.255 8888int main(int argc, const char *argv[]){int ret;int sockfd;int on = 1;char packet[1024];struct sockaddr_in broad_addr;if (argc < 3){fprintf(stderr, "Usage: %s <broadcast ip> <port>\n", argv[0]);exit(EXIT_FAILURE);}// 1. 创建报文套接字sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (-1 == sockfd){perror("Fail to socket.");exit(EXIT_FAILURE);}// 2. 设置套接字广播属性  ret = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));  if (-1 == ret){  perror("Fail to setsockopt.");  exit(EXIT_FAILURE);  }    // 3. 通过广播地址发送数据包到指定端口bzero(&broad_addr, sizeof(broad_addr));broad_addr.sin_family = AF_INET;broad_addr.sin_port = htons(atoi(argv[2]));broad_addr.sin_addr.s_addr = inet_addr(argv[1]);while (1){putchar('\n');putchar('>');fgets(packet, sizeof(packet), stdin);packet[strlen(packet) - 1] = '\0';ret = sendto(sockfd, packet, strlen(packet), 0, (struct sockaddr *)&broad_addr, sizeof(broad_addr));if (-1 == ret){perror("Fail to sendto.");  break;}if (strcmp(packet, "quit") == 0){break;}}// 4. 关闭套接字close(sockfd);return 0;}
recv.c
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <string.h>#include <strings.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>// ./recv 192.168.2.255 8888int main(int argc, const char *argv[]){int ret;int sockfd;char packet[1024];struct sockaddr_in broad_addr;struct sockaddr_in peer_addr;socklen_t addrlen = sizeof(peer_addr);if (argc < 3){fprintf(stderr, "Usage: %s <broadcast ip> <port>\n", argv[0]);exit(EXIT_FAILURE);}// 1. 创建报文套接字sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (-1 == sockfd){perror("Fail to socket.");exit(EXIT_FAILURE);}// 2. 绑定广播地址和端口bzero(&broad_addr, sizeof(broad_addr));broad_addr.sin_family = AF_INET;broad_addr.sin_port = htons(atoi(argv[2]));// broad_addr.sin_addr.s_addr = inet_addr(argv[1]);broad_addr.sin_addr.s_addr = INADDR_ANY;ret = bind(sockfd, (struct sockaddr *)&broad_addr, sizeof(broad_addr));if (-1 == ret){perror("Fail to bind.");exit(EXIT_FAILURE);}while (1){// 3. 接收广播ret = recvfrom(sockfd, packet, sizeof(packet), 0, (struct sockaddr *)&peer_addr, &addrlen);if (-1 == ret){perror("Fail to recvfrom.");break;}packet[ret] = '\0';printf("---------------------------------------\n");printf("ip       : %s\n", inet_ntoa(peer_addr.sin_addr));printf("port     : %d\n", ntohs(peer_addr.sin_port));printf("recv(%d)  : %s\n", ret, packet);printf("---------------------------------------\n");if (strcmp(packet, "quit") == 0){break;}}// 4. 关闭套接字close(sockfd);return 0;}

[3] unix域套接字--流式

    1. 头文件
       #include <sys/un.h>
       
    2. 数据结构
       struct sockaddr_un {
        sa_family_t sun_family;
         // __SOCKADDR_COMMON (sun_);
         
        // #define __SOCKADDR_COMMON(sa_prefix) \                                                              
        // sa_family_t sa_prefix##family     
         // 替换原理,带参数的宏,实参替换形参(整个宏中所有的) 
                                                                   
         char sun_path[108]; // 字符串(unix域套接字文件的名)
       };


    3. 服务端流程
       1. 创建套接字
          sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
          
       2. 绑定地址到socket
struct sockaddr_un server_addr;

server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, "mypath");

ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));

3. 设置为监听模式
   ret = listen(sockfd, 10);
   
4. 接收请求
   clientfd = accept(sockfd, NULL, NULL);
      
5. 接收数据
   ret = recv(clientfd, buf, sizeof(buf), 0);
   
6. 发送数据
   ret = send(clientfd, buf, len, 0);
   
7. 关闭套接字
   close(clientfd);
   close(sockfd);
   
4. 客户端流程
  1. 创建套接字
          sockfd = socket(AF_UNIX, SOCK_STREAM, 0);

server.c

/* * 实现目标: * UNIX域套接字通讯 */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <strings.h>#include <errno.h>#include <pthread.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/un.h>void *handler(void *arg){int ret = 0;int clientfd = (int)(long int)arg;char packet[1024];while (1){// 5. 接收数据ret = recv(clientfd, packet, sizeof(packet), 0);if (-1 == ret){perror("Fail to accept.");break;}packet[ret] = '\0';printf("--------------------------------\n");printf("recv(%d): %s\n", ret, packet);printf("--------------------------------\n");if (strcmp(packet, "quit") == 0){break;}}// 6. 关闭套接字close(clientfd);return (void *)0;}// ./server mypathint main(int argc, const char *argv[]){int ret;int sockfd;int clientfd;pthread_t tid;char packet[1024];struct sockaddr_un server_addr;if (argc < 2){fprintf(stderr, "Usage: %s <path>\n", argv[0]);exit(EXIT_FAILURE);}// 1. 创建套接字sockfd = socket(AF_UNIX, SOCK_STREAM, 0);if (-1 == sockfd){perror("Fail to socket.");exit(EXIT_FAILURE);}// 2. 绑定地址server_addr.sun_family = AF_UNIX;strcpy(server_addr.sun_path, argv[1]);ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));if (-1 == ret){perror("Fail to bind.");exit(EXIT_FAILURE);}// 3. 设置为监听模式ret = listen(sockfd, 10);if (-1 == ret){perror("Fail to listen.");exit(EXIT_FAILURE);}while (1){// 4. 接收连接请求clientfd = accept(sockfd, NULL, NULL);if (-1 == clientfd){perror("Fail to accept.");exit(EXIT_FAILURE);}printf("--------------------------------\n");printf("accept a client\n");printf("--------------------------------\n");    pthread_create(&tid, NULL, handler, (void *)(long int)clientfd);    pthread_detach(tid);}// 6. 关闭套接字close(sockfd);unlink(argv[1]);return 0;}
client.c

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <strings.h>#include <errno.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/un.h>// ./client "mypath"int main(int argc, const char *argv[]){int ret = 0;int sockfd;char packet[1024];struct sockaddr_un server_addr;if (argc < 2){fprintf(stderr, "Usage: %s <path>\n", argv[0]);exit(EXIT_FAILURE);}// 1. 创建监听socketsockfd = socket(AF_UNIX, SOCK_STREAM, 0);if (-1 == sockfd){perror("Fail to socket.");exit(EXIT_FAILURE);}// 2. 连接服务端(connect)server_addr.sun_family = AF_UNIX;strcpy(server_addr.sun_path, argv[1]);ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));if (-1 == ret){perror("Fail to connect.");exit(EXIT_FAILURE);}while (1){putchar('\n');putchar('>');fgets(packet, sizeof(packet), stdin);packet[strlen(packet) - 1] = '\0';// 3. 发送(写)ret = send(sockfd, packet, strlen(packet), 0);if (-1 == ret){perror("Fail to connect.");exit(EXIT_FAILURE);}/* 4. 接收(读)ret = recv(sockfd, packet, sizeof(packet), 0);if (-1 == ret){perror("Fail to connect.");exit(EXIT_FAILURE);}packet[ret] = '\0';printf("--------------------------------\n");printf("recv(%d) : %s\n", ret, packet);printf("--------------------------------\n");*/if (strcmp(packet, "quit") == 0) break;}// 5. 关闭套接字close(sockfd);return 0;}


          
       2. 连接服务器
          struct sockaddr_un server_addr;

server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, "mypath");

ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));

  3. 发送数据
   ret = send(clientfd, buf, len, 0);
   
4. 接收数据
   ret = recv(clientfd, buf, sizeof(buf), 0);
   
5. 关闭套接字
   close(sockfd);
  
[3] unix域套接字--报文
    1. 客户端流程
       1. 创建套接字
          sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
          
       2. 绑定(自己)地址
          struct sockaddr_un self_addr;

self_addr.sun_family = AF_UNIX;
strcpy(self_addr.sun_path, "client_addr");

ret = bind(sockfd, (struct sockaddr *)&self_addr, sizeof(self_addr));

3. 发送/接收
   struct sockaddr_un server_addr;

server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, "server_addr");

   ret = sendto(sockfd, buf, len, 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
   
   
   // 接收
   struct sockaddr_un peer_addr;
   socklen_t addrlen = sizeof(peer_addr);
   
   ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&peer_addr, &addrlen);
   
4. 关闭套接字
   close(sockfd);
   unlink("client_addr");
       
    2. 服务端流程
       1. 创建套接字
          sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
          
       2. 绑定(自己)地址
          struct sockaddr_un self_addr;

self_addr.sun_family = AF_UNIX;
strcpy(self_addr.sun_path, "server_addr");

ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));

  3. 接收
     struct sockaddr_un peer_addr;
   socklen_t addrlen = sizeof(peer_addr);
   
   ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&peer_addr, &addrlen);
   

4. 发送
   ret = sendto(sockfd, buf, len, 0, (struct sockaddr *)&peer_addr, sizeof(peer_addr));
   
5. 关闭
   close(sockfd);
   unlink("server_addr");

client.c

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <strings.h>#include <errno.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/un.h>// ./server client_addr server_addrint main(int argc, const char *argv[]){int ret = 0;int sockfd;char packet[1024];struct sockaddr_un server_addr;struct sockaddr_un peer_addr;socklen_t addrlen = sizeof(server_addr);if (argc < 3){fprintf(stderr, "Usage: %s <client addr> <server addr>\n", argv[0]);exit(EXIT_FAILURE);}// 1. 创建套接字sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);if (-1 == sockfd){perror("Fail to socket");exit(EXIT_FAILURE);}  // 2. 绑定(自己)地址peer_addr.sun_family = AF_UNIX;strcpy(peer_addr.sun_path, argv[1]);ret = bind(sockfd, (struct sockaddr *)&peer_addr, sizeof(peer_addr));if (-1 == ret){perror("Fail to bind");exit(EXIT_FAILURE);}server_addr.sun_family = AF_UNIX;strcpy(server_addr.sun_path, argv[2]);  while (1){    putchar('\n');  putchar('>');  fgets(packet, sizeof(packet), stdin);  packet[strlen(packet) - 1] = '\0';    // 3. 发送(写)  ret = sendto(sockfd, packet, strlen(packet), 0, (struct sockaddr *)&server_addr, sizeof(server_addr)); if (-1 == ret){ perror("Fail to sendto."); break; }  printf("-----------------------------\n"); printf("send : %s\n", packet); printf("-----------------------------\n");     // 4. 接收(读)  ret = recvfrom(sockfd, packet, sizeof(packet), 0, (struct sockaddr *)&server_addr, &addrlen);  if (-1 == ret){  perror("Fail to recvfrom."); break;  }  packet[ret] = '\0';  printf("-----------------------------\n");printf("recv(%d): %s\n", ret, packet);printf("-----------------------------\n");   if (strcmp(packet, "quit") == 0){  break;  }}    // 5. 关闭  close(sockfd);  unlink(argv[1]);return 0;}
server.c

#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <strings.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/un.h>// ./server server_addrint main(int argc, const char *argv[]){int ret = 0;int sockfd;char packet[1024];struct sockaddr_un server_addr; struct sockaddr_un peer_addr;socklen_t addrlen = sizeof(peer_addr);if (argc < 2){fprintf(stderr, "Usage: %s <src addr>\n", argv[0]);exit(EXIT_FAILURE);}// 1. 创建套接字sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);if (-1 == sockfd){perror("Fail to socket.");exit(EXIT_FAILURE);}// 2. 绑定(自己)地址server_addr.sun_family = AF_UNIX;  strcpy(server_addr.sun_path, argv[1]);ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));if (-1 == ret){perror("Fail to bind.");exit(EXIT_FAILURE);}  while (1){// 3. 接收数据包ret = recvfrom(sockfd, packet, sizeof(packet), 0, (struct sockaddr *)&peer_addr, &addrlen);if (-1 == ret){perror("Fail to recvfrom.");break;}packet[ret] = '\0';printf("-----------------------------\n");printf("from   : %s\n", peer_addr.sun_path);printf("recv(%d): %s\n", ret, packet);printf("-----------------------------\n");// 4. 发送数据包ret = sendto(sockfd, packet, ret, 0, (struct sockaddr *)&peer_addr, sizeof(peer_addr));if (-1 == ret){perror("Fail to sendto.");break;}if (strcmp(packet, "quit") == 0){break;}}// 5. 关闭close(sockfd);unlink(argv[1]);return 0;}

0 0
原创粉丝点击