• Linux系统/网络 笔记


    1 内存共享 
        内存的获取
            int fd = shmget(key_t key ,size_t size , int shmflg);
    
        内存的关联
            void* shmat(int shmid ,const void* shmaddr , int shmflg);
    
            char *p;
             p = (char*) shmat(fd , 0 , 0 );
    
        内存的分离
            int shmdt(const void* shmaddr);
    
        内存的控制
    
            int shmctl(int shmid , int cmd , struct shmid_ds* buf);
    
            ret = shmctl(fd, IPC_RMID, NULL);
                    cmd : IPC_STAT 获取当前状态 返回给参数3
                          IPC_SET  设置共享内存
    
    
    2.多路复用
    
            select系统调用
    
        int ret =  select (int  nfds, fd_set* readfds, fd_set* write , 
                                                fd_set* exceptfds, struct timeval* timeout );
    
        nfds = 监听的文件描述符最大值+1;
    
        文件描述符集:fd_set
    
            FD_ZERO :清空集合                      RD_ZERO(&read_set);
            FD_CLR  :把指定的文集描述符从集合删除  FD_SET(fd ,&read_Set); 
            FD_SET  :添加指定的文件描述符到集合
            FD_ISSET:监测指定的文件描述符是否在集合中
    
        struct timeval{
                long tv_sec;    超时 秒设置
                long tv_usec ;  超时 微微秒设置
            }
    
        监听到 ret > 0 
            在用 FD_ISSET(fd , &read_set)  监测 fd 是否在文件集合中
    
    
        3 .信号量
    
            信号量的获取:
                int  semget(key_t key , int nsems , int semflg); 
    
                返回值为该信号量的标识符
                nsmes 需要的信号数目 一般取1;
                IPC_CREAT | 权限
    
            信号的初始化
    
                int semctl(int semid , int sem_num , int cmd , ....);
    
                semid 信号的标识符 
                sem_num 信号量组中的编号  如果只有一个信号 取值为 0
                cmd  : SETVAL 表示初始化信号量  具体参数由第四个参数确定
                        信号量只能初始化一次
                    :IPC_RMID  表示删除;
    
                第四个参数:
                    union semun{
                        int  val    : // sETVAL 要设置的值
    
                        struct semid_ds* buf ;    0;
                        unsigned short* array ;   0;
                    }       
    
            注意 union semun 联合体需要自己定义
    
        信号量的操作  V——P
                int semop(int semid , struct sembuf* sops , unsigned nsops);
    
                sops  是 一个数组, 元素类型为 struct sembuf 
                        struct sembuf {
                            short sem_num ; 只有一个  取0short sem_op ;  // -1,表示P 操作哦
                                            // 1 表示V 操作
                            short sem_flg ;  0;
                        }       
                nsops     表示有几个 struct sembuf ;
    
    
    4 线程
    
            同一个进程内的各个线程,能够共享整个进程的全局变量 ,除了线程的局部变量外, 其他资源都是共享的
    
            线程的创建:
    
                pthread_t  pthread_fd;
    
                int  ret  = pthread_create( pthread_t pthread_fd, pthread_att_t* attr , 
                                            void*(*start_routine)(void*)  , void* arg );
                attr 设置线程的属性   一般取默认 NULL;
    
                start_routine   该线程的处理函数 
                                    该函数的返回类型和参数类型都是void*
    
                arg  线程处理函数 start_routine 的参数;
    
        : 创建一个线程 : 同时指定该线程的属性 执行函数 执行函数的参数 
                                            通过参数1返回该线程的标识符
    
    
    
            线程的终止
                   void  pthread_exit(void * retval);
                    在线程函数内部调用该函数
                        终止该线程, 并通过参数retval 返回一个指针
                            该指针不能指向该线程的局部变量
    
    
            等待指定线程的结束
             int pthread_join(pthread_t th , 
                                    void** thread_return);
                thread_return  指向该线程函数的返回值
    
    
    
    
    
    //===================================网络编程==============================================
    
    OSI ---- ISO
            物理层    比特流      RS-232     网卡 
    
            数据链路层    帧(frame)  交换机   
    
            网络层     选择最佳的路径到达目的地    路由器
    
            传输层     提供可靠的数据传输服务(监测路由器丢弃的包)  提供重传机制   包的排序
    
            会话层     管理主机之间的会话过程    会话的建立  会话的终止  会话过程的管理
    
            表示层     数据压缩 格式转换   加密  
    
            应用层     与应用程序之间通讯
    
    
    
    
            链路层   ARP -----RARP     协议
    
            网络层
    
            传输层
    
            应用层
    
    ==------------------------------------------------------------------------
        对等通信     虚电路
        TCP/IP  协议栈
    
    ==-----------------------------------------------------------------------
    
    
          封装:   用户数据  ----> app + 数据 ----> TCP+app+数据 ---> IP+TCP+app+数据 ---->以太网首部+IP+TCP+app---网络
    
          解封:       
    ===-----------------------------------------------------------------------
        端口   1-1023  系统
               1024 - 49151 
               49152-65535
    
    
        端口决定同一台主机IP 分别传送数据给哪个应用程序          
    
    ===-------------------------------------------------------------------------
    
    
    链路层  : 最大传输单元   MTU        46-----1500字节        CRC尾部 校对 
    
                ICMP    协议         差错的信息的控制  查询信息的控制  ping————》将数据封装成ICMP 协议实现的      
                                        地址解析无法完成  使用ICMP 协议 查找MAC硬件地址       
    
    
                ARP    地址解析协议
                RARP    反向
    
                IP地址  只是逻辑上的地址  IP--->MAC   地址解析(ARP) 
    ===-----------------------------------------------------------------------
    以太网帧的格式  : 
                目的地址  : 
    
                源地址    : 
    
                帧类型     :     IP数据包(0800)    ARP(0806)    RARP(8035)   3种 
    
                硬件类型 :
    
                协议类型 :
    
                硬件地址长度 :
    
                协议地址长度 :
    
                OP      :
    
                发送端以太网地址 :
    
                发送端IP地址  :
    
                目的以太网地址 :
    
                目的IP地址 :
    
    ===-----------------------------------------------------------------------------
    1.      ping ----主机名 -----调用函数 gethostbyname()   将主机名转化为一个32位的IP地址
                 ----iP地址    
    
    2.      向目的IP地址发送一个ICMP 的ECHO 包 
    
    3.      将主机IP地址转换为48位的硬件地址    在局域网内发送ARP 请求广播  查找主机的硬件地址
    
    4.      主机B ARP 协议层接收到主机A 的ARP 请求后 ,将本机的硬件地址添加到应答包  发送ARP应答到主机A 
    
    5.      (ARP高速缓存保存 B 地址    B 保存A地址)
            发送ICMP 数据包到主机B
    
    6.      主机B收到A 的ICMP 包   发送响应包
    
    7.      主机A收到B 的ICMP 响应包
    
    
    ===-----------------------------------------------------------------------------------
    
    
    ====================================TCP/IP =======================================================
    首部长度为  15*4 = 60 
    
    
    TLL   数据报的生存期    每经过一个路由器TLL 减一   为0 时丢弃  并发送ICMP报文通知源主机
    
    协议类型     1 ICMP  2 IGMP    6 TCP  17 UDP     
    
    
    每经过一个路由器 IP报的头部都会发生改变 
    
    ===----------------------------------------------------------------------------------------
    网际校验和  
        IP首部(不含校验和)反码+ )+0X 1111 
    ===----------------------------------------------------------------------------------------
    
    路由  
    
        用源IP与源SubnetMask相与  , 用目的IP 和SubnetMask相与 看看他们是不是相等 在同一局域网中
    
    ==------------------------------------------------------------------------------------------
    基于字节流的传输服务   magment  没有边界 
    
    面向链接  
    
    可靠的传输服务         端到端的校验和
    
    缓冲传输            
    
    全双工的传输服务
    
    提供流量控制功能
    
    ==------------------------------------------------
    
    IP 报文格式  : IP头部 + TCP头部 + TCP 数据
    
    TCP 格式  :TCP头部 + TCP 数据 
    
    TCP 头部 : 源端口  + 目的端口    (都为16位)
    
    
    ====----------------------------------------------
    远端口 与目的端口  : + IP首部的源IP地址和目的IP地址 唯一确定一个TCP 链接
    
    
    序号 : 报文段的第一个数据字节序号
    
    确认号 : ACK 
    
    ===-----------------------------------------------
    三次握手 :
            A : 发送 序列号为 a  TCP段 给 B;
    
            B :发起链接 序列号为 b  确认号为 a+1 (希望A回复的序列号为a+1)
    
            A :序列号为a+1 , 确认号为b+1 (希望B在回复的序类号 为b+1)  
    
    
    ===------------------------------------------------
    四次挥手 :  FIN 位 为1
            A : 调用close()函数  序号为 X 表示希望B回复时序列号为 Y  
    
            B : 回复A 序列号为Y  ACK 为Q希望收到A回复序列号为Q
    
            B : FIN为1  发送断开请求  序列号为 X ACK 为Q (希望A回复序列号为Q)
    
            A : 发送 序列号为Q ACK 为(X+1) 希望B回复序列号为X+1 ;
    
    
    ===-----------------------------------------------------
    差错       端到端的校验和
    
    丢包    超时重传     
    
    失序      排序号
    重复
    
    数据-----分割成TCP认为最适合发送的数据块 ---发送一个段后---启动定时器---等待确认-----超时重发      
    
    
    TCP 校验发生错误  需要重新传送
    
    流量控制 -------- 滑动窗口
    
    
    累积字节  确认机制     
    
    
    慢启动  
    
    拥塞
    
    ==-------------------------------------------------
    IP 数据 : IP头部  + UDP头部 + UDP数据 
    
    
    
    =============================================================socket ==========================================
    
    app ---socket----[TCP ----IP ---inet]----->>>>>
                              |
                              |   
                        内核已实现
    
    socket ------用户进程与内核网络协议栈的编程接口
    
    sockaddr_in  :
            uint8_t   sin_len;
    
            sa_family_t sin_family ;
    
            in_port_t  si_port ;
    
            struct in_addr sin_addr ;
    
            char sin_zero[8];
    
    
    通用地址结构 :
    
        struct sockaddr {
            uint8_t   sin_len;
            sa_family_t  sin_family ;
    
            char sa_dat[14];
    
        };
    
    ===------------------------------------------------------------------------------------------------
    字节序  :
            uint32_t  htonl();
            uint16_t  htons();
    
    #include <netinet/in.h>
    #include <arpa/inet.h>
    
            inet_addr(char*)    ;   
            inet_ntoa(struct in_addr  in);
    
    
    
    ===--------------------------socket---------------------------====
    回射客户服务器  
            stdin ------->fgets -------TCP客户--->write----->read--->TCP服务器
    
            stdout<------fputs <-------TCP客户<---read ------<write<--TCP服务器
    
    
    int socket(int domain , int type ,  int protcocol);
    
            AF_INET  
    
            SOCK_STREAM   SOCK_DGRAM
    
            0 
    #include <sys/types.h>
    #include <sys/socket.h>
    
    
        int  bind (int sock , (struct sockaddr*) &serveraddr , sizeof(struct sockaddr_in));
    
    
        serveraddr.sin_family = AF_INET ;
    
        serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
        serveraddr.sin_addr.s_addr = inet_addr("127.186.0.8");
        inet_aton("127.0.89.0", &serveraddr.sin_addr);
    
        serveraddr.sin_port = htons(8000);
    
    ==--------------------------------------------
    #include <sys/socket.h>
    
        int listen(int sock , int backlong)
    
        backlong 为监听的数  最大为20  10   5 
    
    return  成功为 0  ,失败为 -1 ;
    
    ==-----------------------------------------
    被动套接字  : 接收链接  
    
    
    主动套接字   :发送数据
    
    int sockfd = accept (int sock , struct sockaddr* addr , socklen_t *addr_len );
    
    失败  返回 -1;
    
    ==-----------------------------------------
    int connect(int sock , const struct sockaddr* addr , socklen_t addlen);
    
    IP地址和端口 决定一个链接  
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    int inet_aton(const char *cp, struct in_addr *inp);
    in_addr_t inet_addr(const char *cp);
    in_addr_t inet_network(const char *cp);
    char *inet_ntoa(struct in_addr in);
    struct in_addr inet_makeaddr(int net, int host);
    in_addr_t inet_lnaof(struct in_addr in);
    
    ===----------------------------------------------
    REUSEADDR   用法  消除服务器关闭后马上启动时   TIME_WAIT 状态 
    
    ==-----------------------------------------------
    server 进程实现
        pid_t pid ;
    
    
        pid = fork();
    
        if(pid == -1){
              perror(pid);
        }else if(pid == 0){
            while(1){
    
            }
    
        }
    
    ret = read(sock , buff , BUFF_LEN);
    if(ret == 0){
        cout << "捕捉客户端关闭"<< endl;
    }
    
    sock三次握手完成  放到listen队列中  
    ==-------------------------------------------------------
    聊天程序
        注意僵尸进程的产生
    
    ==------------------------------------------------------
    
    write --> 复制消息到内核 BUFF(内核缓存)---->MSS<MTU-40 ----> IP层 分包------>
    
    
    
        ssize_t readn(int fd , void* buff , size_t count ){
            size_t  nleft = count ;
            ssize_t nread;
            char* bufp = (char*)buff;
    
            while(nleft > 0){
                if((nread == read (fd , bufp , nleft)) < 0){
                    if(errno == EINTR )
                        continue ;
                    return -1;
                }else if (nread == 0){
                    return count -nleft ;
                }
                bufp +=nread ;
               nleft -=nread ;              
            }
        return count ;
        } 
    
    =
    =----------------------------------------------------
    #include <arpa/inet.h>
    
    uint32_t htonl(uint32_t hostlong);
    uint16_t htons(uint16_t honsshort);
    
    
    uint32_t ntohl(uint32_t hostlong);
    uint16_t ntohs(uint16_t honsshort);
    
    
    如果发送的不是字符 而是数的时候  必须将 数转换为网络字节序  htonl();
        接收时                       必须将 网络字节序转换为主机字节序 ntohl();
    
    
    ret = read(sockfd , &n , 4);
    
    len = ntohl(n);   //将网络字节序转化为主机字节序
    
    ret = read(sockfd , buff, len );
    
    ==----------------
    struct info {
        size_t len;
        char* buff[1024]={0};
    }info;
    memset(buff , "hellword");
    
    info.len = htonl(strlen(buff));
    
    ret = write (sockfd , (void*)&info , 4+strlen(buff));
    
    ==---------------------------------------------------------
    recv send  readline  getsockname   getpeername  gethostname gethostbyname gethostbyaddr
    
    
    recv  只能用于套接口 不能用于文件套接字  
    
        ret = read (sockfd  , &info.len , 4);
    
        if(ret == -1 && error == EINTR)
            continue ;
    
        return ret ;
    
    
    ftp  格式:    
    readline 只能用于套接口 
    
        int ret ;
        int nread;
        char * bufp = buff;
        int nleft = maxline ;
        while(1){
            ret = recv_peek (sockfd , bufp , nleft );
    
            if(ret < 0){
                return ret ;
            }
            if(ret == 0){
                return 0;
            }
            nread = ret ;
    
            int  i=0;
            for(i=0 ; i < nread ; i++){
                if(bufp[i] == '
    '){
                    ret = readn(sockfd , bufp , i+1);
                    if(ret != i+1){
                        exit(EXIT_FAILURE);
                    }
                    return ret ;
                }           
            }
        if(nread > nleft )
            exit(EXIT_FAILURE);
    
        nleft -= nread ;
    
        ret = readn(sockfd , bufp , nread );
        if(ret != nread ){
            exit(EXIT_FAILURE);     
        }
    
        }
    
    ==----------------------------------------------------------
    getsockname()   获取本地地址以及端口号
    
    
    getpeername ()  获取链接对方的地址和端口号
    
    #include <sys/socket.h>
    int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    
    #include <sys/socket.h>
    int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    
    
    #include <netdb.h>
    extern int h_errno;
    struct hostent *gethostbyname(const char *name);
    
    #include <sys/socket.h>       /* for AF_INET */
    struct hostent *gethostbyaddr(const void *addr,socklen_t len, int type);
    
    void sethostent(int stayopen);
    void endhostent(void);
    void herror(const char *s);
    
    ====----------------------------------------------------------------
    僵死进程的管理控制
        #include <signal.h> 
        sighandler_t signal(int signum, sighandler_t handler);  
    
    
    
        signal(SIGCHLD, SIG_IGN);       //忽略信号
    
        signal(SIGCHLD, handle_sigchld);
    
        signal(SIGPIPE, SIG_IGN)  
        当服务器close一个连接时,若client端接着发数据。
        根据TCP 协议的规定,会收到一个RST响应,client再往这个服务器发送数据时,
        系统会发出一个SIGPIPE信号给进程,告诉进程这个连接已经断开了,不要再写了。 
        根据信号的默认处理规则SIGPIPE信号的默认执行动作是terminate(终止、退出),所以client会退出。
        若不想客户端退出可以把SIGPIPE设为SIG_IGN 
        如:    signal(SIGPIPE,SIG_IGN); 
        这时SIGPIPE交给了系统处理。 
        服务器采用了fork的话,要收集垃圾进程,防止僵尸进程的产生,可以这样处理: 
        signal(SIGCHLD,SIG_IGN); 交给系统init去回收。 
        这里子进程就不会产生僵尸进程了。
    
    void handle_sigchld(int sig){
        while(waitpid(-1,NULL , WNOHANG(不挂起)) > 0)  //循环 保证所有SIGCHLD 信号都wait 
        没有子进程返回时  返回-1  导致循环退出
    
        }
    完美解决僵尸进程
    
    
    ==-----------------------------------------------------------------
    NNUIX 套接字:
    
    socketpair(PF_UNIX ,SOCK_STREAM, 0 ,sockfd ) //  可以实现文件套接字 信息的传递
    #include <sys/types.h>
    #include <sys/socket.h>
    
    ssize_t send(int sockfd, const void *buf, size_t len, int flags);
    ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                       const struct sockaddr *dest_addr, socklen_t addrlen);
    ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
    
    
    
    #include <sys/types.h>
    #include <sys/socket.h>
    ssize_t recv(int sockfd, void *buf, size_t len, int flags);
    ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                            struct sockaddr *src_addr, socklen_t *addrlen);
    ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
    
    
    
    
    ====----------------------------------------------------------------------------
    POSIX 进程的通信:
    System V 进程间通信:
    
    
        文件:
        文件锁:
        管道: pipe    命名管道 FIFE      传输的是字节流没有边界的
        信号: signal
        消息队列: 
        内存共享:
        信号量:
        互斥量:
        条件变量:
        读写锁:
        套接字:
    
    ==------------------------------------------------------------------------
    消息队列:
        int msgget(key_t  key , int msgflg);
        int msgctl(int msgfd , int cmd , struct msgid_ds* buff);
    ===-----------------------------------------------------------------------
    DMA  控制  cpu----不参与
    
    ==----------------------------------------------------------------------
    用户-------发送信息 -----内核-----应用程序
    
    cup  MNU + linux
    
    
    逻辑地址 
    
    
    网络内嵌内核  主要防止产生大量的终段 
    
    close tcp ip   五种服务器模型
    
    段式管理和页式管理
    逻辑地址空间------》物理地址 
    分时操作系统-----时间片段的轮转
    
    
    
    ==------------------------------进程三态--------------------
    VFS  虚拟文件系统
    
    
    
    创建  -----------------就绪
    运行------------------调度
    I/O -----------------等待
    
    
    --------------------------------------------------
    进程的状态 :
        运行----TASK_RUNING 
        可中断 ---TASK_INTERRUPTBLE
        不可中断 ---TASK_UNINTERRUPTBL
        暂停 ------TASK_STOPPED
        僵死 ------TASK_ZOMBIE
    
    
    ps -ef   
    
    0 号进程 -----内核
    
    进程函数终止的五种状态:
                _exit();
                exit();
    0 --- 正常退出
    1-----异常退出
    
    
    
    fork();
    execl();
    
    int atexit(void(* function)(void));
    
    
    ===============================================
    
    emon函数的用法
    
    说明:
    
    让一个程序后台运行。
    
    原型:
    
    [c-sharp] view plaincopy
    
        #include <unistd.h>  
    
        int daemon(int nochdir, int noclose);  
    
        参数:
    
        当 nochdir为零时,当前目录变为根目录,否则不变;
    
        当 noclose为零时,标准输入、标准输出和错误输出重导向为/dev/null,也就是不输出任何信 息,否则照样输出。
    
        返回值:
    
        deamon()调用了fork(),如果fork成功,那么父进程就调用_exit(2)退出,所以看到的错误信息 全部是子进程产生的。如果成功函数返回0,否则返回-1并设置errno。
    
        #include <stdio.h>  
            #include <stdlib.h>  
            #include <unistd.h>  
            #include <fcntl.h>  
            #include <limits.h>  
    
            int main(int argc, char *argv[])  
            {  
                        char strCurPath[PATH_MAX];  
    
                                if(daemon(1, 1) < 0)  
                                            {  
                                                            perror("error daemon.../n");  
                                                                        exit(1);  
                                                                                }  
                                        sleep(10);  
    
                                                if(getcwd(strCurPath, PATH_MAX) == NULL)  
                                                            {  
                                                                            perror("error getcwd");  
                                                                                        exit(1);  
                                                                                                }  
                                                        printf("%s/n", strCurPath);  
                                                                return 0;  
                                                                    }  
    
    
    ==----------------------------------------------------------------------------
    守护进程  :setsid();     创建一个进程  在子进程中调用setsid();   pid = setsid();
    
                :daemon();      daemon() 已近包含了fork()   pid= daemon(1,1) ,if pid > 0 创建成功
    
    
    会话期   组长
    
    =====-------------------------------------------------------------------------------
     子进程退出时向父进程发送一个信号   SIGCHLD 
    
    
     ==-----------------------------------------------------------------------------
     system :   fork------>excel------->waitpid();
    
    ==--------------------------------------------------------------------------------
    中断信号  :
        signal()
        sigaction();
    
        int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
    
    ===-------------------------------------------------------------------------------
    
    shell:
        find :  find -name  "*.*";
        grep :  按行查找 
        awk  :  按列查找
        sed  :  编辑 替换     sed  '1,3' 
                              sed  's/s1/s2/g'
    
    ==-------------------------------------------------------------------------------
    共享内存  :ipcs  ---
                共享内存被占用的时候 ,不会马上删除。
  • 相关阅读:
    CF_402C Searching for Graph 乱搞题
    zoj Simple Equation 数论
    zoj 3757 Alice and Bob and Cue Sports 模拟
    uva_12535
    boj1267 Infinite’s Cave 树形dp + 背包
    CF_216_Div_2
    nxlog4go 简介
    log4go的一些改进设想
    nxlog4go 的配置驱动
    nxlog4go Log Levels and Pattern Layout
  • 原文地址:https://www.cnblogs.com/Sico2Sico/p/5384274.html
Copyright © 2020-2023  润新知