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] == '\n'){
                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  ---
            共享内存被占用的时候 ,不会马上删除。
posted @ 2016-03-28 00:48  夜色下的港湾  Views(217)  Comments(0Edit  收藏  举报