(笔记)第十七节课:信号灯&网络编程

(笔记)第十七节课:信号灯&网络编程,第1张

一 IPC通信之 信号灯集

信号灯集:是在内核空间的信号灯的集合

 

 

1.1 信号灯集函数接口 1.semget

头文件:#include       #include        #include 原型:int semget(key_t key, int nsems, int semflg);功能:创建或者打开一个信号灯集参数:    key:信号灯集的秘钥(和共享内存,消息队列类似)    nsems:创建的信号灯集中存在几个信号灯    semflg:打开的方式        IPC_CREAT:如果共享内存存在,则打开,不存在则创建        例如:IPC_CREAT | 0664        IPC_EXCL:如果存在则报错返回,如果不存在配合IPC_CREAT创建返回值:    成功返回一个信号灯集的ID    失败返回-1

2.semctl

头文件:#include       #include        #include        原型:int semctl(int semid, int semnum, int cmd, ...);功能:控制信号灯集参数:    semid:要控制的信号灯集的ID号    semnum:信号灯的编号    cmd:控制方式        IPC_RMID:删除信号灯集,不考虑第二个参数        GETVAL:获取信号灯的值        SETVAL:设置信号灯的值    ..:可变参数:是一个联合体        union semun {               int              val;    /* Value for SETVAL */               struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */               unsigned short  *array;  /* Array for GETALL, SETALL */               struct seminfo  *__buf;  /* Buffer for IPC_INFO                                           (Linux-specific) */           };          返回值:    成功返回 0    GETVAL:返回一个信号灯的值    失败返回-1

3.封装初始化函数

int sem_init_val(int semid,int semnum,int val){    union semun myval;  //需要自己定义    myval.val = val;    if(-1 ==semctl(semid,semnum,SETVAL,myval))    {        printf("初始化信号灯%d失败\n",semnum);        return -1;       }    return 0;}

4. semop

头文件:#include       #include        #include        原型:int semop(int semid, struct sembuf *sops, size_t nsops);功能: *** 作方式参数:semid:信号灯集的ID号sops: *** 作方法结构体的地址    unsigned short sem_num;  /* semaphore number */    short          sem_op;   /* semaphore operation */    short          sem_flg;  /* operation flags */    使用案例:         struct sembuf sops[2];           int semid;           /* Code to set semid omitted */           sops[0].sem_num = 0;        /* Operate on semaphore 0 */           sops[0].sem_op = 0;         /* Wait for value to equal 0 */           sops[0].sem_flg = 0;           sops[1].sem_num = 0;        /* Operate on semaphore 0 */           sops[1].sem_op = 1;         /* Increment value by one */           sops[1].sem_flg = 0;           if (semop(semid, sops, 2) == -1) {               perror("semop");               exit(EXIT_FAILURE);           }nsops:同时 *** 作的个数    如果说同时 *** 作很多信号灯,填写一个结构体数组                                    返回值:    成功返回0    失败返回-1

//write#include #include #include #include #include union semun {    int  val;    /* Value for SETVAL */};int sem_init_val(int semid,int semnum,int val){    union semun myval;  //需要自己定义    myval.val = val;    if(-1 ==semctl(semid,semnum,SETVAL,myval))    {        printf("初始化信号灯%d失败\n",semnum);        return -1;       }    return 0;}int sem_p(int semid,int semnum) //参数1:信号灯集  2.信号灯的编号{       struct sembuf mybuf;    mybuf.sem_num = semnum;        /* Operate on semaphore 0 */    mybuf.sem_op = -1;         /* Wait for value to equal 0 */    mybuf.sem_flg = 0;    if(-1 == semop(semid,&mybuf,1))    {        printf("p *** 作失败\n");        return -1;    }    return 0;}int sem_v(int semid,int semnum) //参数1:信号灯集  2.信号灯的编号{       struct sembuf mybuf;    mybuf.sem_num = semnum;        /* Operate on semaphore 0 */    mybuf.sem_op = 1;         /* Wait for value to equal 0 */    mybuf.sem_flg = 0;    if(-1 == semop(semid,&mybuf,1))    {        printf("v *** 作失败\n");        return -1;    }    return 0;}int main(int argc, char const *argv[]){    //生成一个共享内存使用的key值    key_t mykey1 = ftok("/home/jsetc/jsetc/208/",'a');    if(-1 == mykey1)    {        perror("生成键值失败");        return -1;    }    //生成一个自定义key值    key_t mykey = ftok("/home/jsetc/jsetc/208/day17/",'a');    if(-1 == mykey)    {        perror("ftok");        return -1;    }    //创建信号灯集    int semid = semget(mykey,2,IPC_CREAT | 0664);    if(-1 == semid)    {        perror("semget");        return -1;    }    //初始化信号灯集    sem_init_val(semid,0,1);    sem_init_val(semid,1,0);    //创建共享内存    int shmid = shmget(mykey1,4096,IPC_CREAT | 0664);    if(-1 == shmid)    {        perror("shmget");        return -1;    }    printf("创建或者打开共享内存成功\n");    //地址映射    char *buf = (char *)shmat(shmid,NULL,0);    if((char *)-1 == buf)    {        perror("shmat");        return -1;    }    while(1)    {        sem_p(semid,0);    //p *** 作        printf("请输入\n");        scanf("%s",buf);        sem_v(semid,1);    }        return 0;}

#include #include #include #include #include union semun {    int  val;    /* Value for SETVAL */};int sem_init_val(int semid,int semnum,int val){    union semun myval;  //需要自己定义    myval.val = val;    if(-1 ==semctl(semid,semnum,SETVAL,myval))    {        printf("初始化信号灯%d失败\n",semnum);        return -1;       }    return 0;}int sem_p(int semid,int semnum) //参数1:信号灯集  2.信号灯的编号{       struct sembuf mybuf;    mybuf.sem_num = semnum;        /* Operate on semaphore 0 */    mybuf.sem_op = -1;         /* Wait for value to equal 0 */    mybuf.sem_flg = 0;    if(-1 == semop(semid,&mybuf,1))    {        printf("p *** 作失败\n");        return -1;    }    return 0;}int sem_v(int semid,int semnum) //参数1:信号灯集  2.信号灯的编号{       struct sembuf mybuf;    mybuf.sem_num = semnum;        /* Operate on semaphore 0 */    mybuf.sem_op = 1;         /* Wait for value to equal 0 */    mybuf.sem_flg = 0;    if(-1 == semop(semid,&mybuf,1))    {        printf("v *** 作失败\n");        return -1;    }    return 0;}int main(int argc, char const *argv[]){    //生成一个共享内存使用的key值    key_t mykey1 = ftok("/home/jsetc/jsetc/208/",'a');    if(-1 == mykey1)    {        perror("生成键值失败");        return -1;    }    //生成一个自定义key值    key_t mykey = ftok("/home/jsetc/jsetc/208/day17/",'a');    if(-1 == mykey)    {        perror("ftok");        return -1;    }    //创建信号灯集    int semid = semget(mykey,2,IPC_CREAT | 0664);    if(-1 == semid)    {        perror("semget");        return -1;    }    //初始化信号灯集    sem_init_val(semid,0,1);    sem_init_val(semid,1,0);    //创建共享内存    int shmid = shmget(mykey1,4096,IPC_CREAT | 0664);    if(-1 == shmid)    {        perror("shmget");        return -1;    }    printf("创建或者打开共享内存成功\n");    //地址映射    char *buf = (char *)shmat(shmid,NULL,0);    if((char *)-1 == buf)    {        perror("shmat");        return -1;    }    while(1)    {        sem_p(semid,1);    //p *** 作        printf("buf = %s\n",buf);        sem_v(semid,0);    }        return 0;}

二 网络编程 2.1 为什么要学习网络编程

网络编程就是最后一种进程间通信的方式-----》套接字通信

套接字通信:前六种进程间通信只能实现同一台主机的多个进程通信,但是套接字通信可以实现不同主机的多个进程间通信。


2.2 发展

Arpanet

TCP/IP协议:一共两个协议

网络体系结构:发明了osi开放系统互联模型

TCP/IP协议族:有很多个协议组成

2.2.1 ARPnet

是网络的最早雏形

不能互联不同类型的计算机和不同类型的 *** 作系统,没有纠错功能。


2.2.2 TCP/IP协议

TCP/IP协议分成了两个不同的协议:

用来检测网络传输中差错的传输协议:TCP

专门分则对不同网络进行互联的互联网协议:IP

2.3 网络体系结构以及OSI开放系统互联模型

OSI(国际标准化组织)提供的一个网络体系结构

OSI因为层次结构比较复杂,所以到目前也没有使用,但是他是最早提出的网络体系结构

OSI七层模型:

应用层: 面向用户的,应用程序表示层:对数据进行加密和解密会话层:建立逻辑名字和物理名字之间的关系运输层:用于控制数据的有效传输网络层:数据分组,路由选择数据链路层:将数据组成发送或者接收的帧数据物理层:选择物理介质    注意:每个层次之间的顺序是不能改变的

2.4 TCP/IP协议族

后期基于OSI发明了TCP/IP协议族,这个协议族由很多协议组成:

TCP/IP协议族一共四层:

应用层:telnet,www,FTP,TFTP,SIP传输层:tcp udp网络层:IP,ICMP网络接口与物理层:网卡驱动,物理接口

2.5 五层模型

应用层:传输层:网络层:数据链路层:物理层:

2.6 TCP和UDP的异同点

相同点:    同为传输协议不同点:    TCP是面向连接的,可靠的,基于字节流的传输协议    UDP是面向无连接,不可靠的,基于数据报的传输协议Tcp的概念    是一种面向链接的传输协议,它能提供高可靠性的通信(即数据无误,数据不丢失,数据无失序,数据无重复的到达),TCP有回传机制    使用情况:        适合对于传输质量要求较高,以及传输大量数据的通信,比图MSN/QQ登录,账号管理时需要使用TCP协议UDP的概念    是不可靠的,无连接的传输协议,在数据发送前,因为不需要进行链接,所以可以高效率的数据传输    使用情况:        适用于对于实时性要求较高的场景,比如:流媒体

2.7 函数讲解 2.7.1 socket

头文件:#include           /* See NOTES */       #include 原型:int socket(int domain, int type, int protocol);功能:创建套接字,返回一个文件描述符参数:    domain:通信域       AF_UNIX, AF_LOCAL   Local communication              unix(7)   //本地通信       AF_INET             IPv4 Internet protocols          ip(7)    //ipv4网络协议       AF_INET6            IPv6 Internet protocols          ipv6(7)   //ipv6网络协议       AF_IPX              IPX - Novell protocols       AF_NETLINK          Kernel user interface device     netlink(7)       AF_X25              ITU-T X.25 / ISO-8208 protocol   x25(7)       AF_AX25             Amateur radio AX.25 protocol       AF_ATMPVC           Access to raw ATM PVCs       AF_APPLETALK        AppleTalk                        ddp(7)       AF_PACKET           Low level packet interface       packet(7)   //底层协议通信       AF_ALG              Interface to kernel crypto API    type:套接字类型       SOCK_STREAM   :流式套接字   --->tcp         SOCK_DGRAM   : 数据报套接字 --->udp       SOCK_RAW :      原始套接字    protocol:附加协议,传0表示不需要其他协议返回值:    成功:文件描述符    失败: -1

2.7.2 bind()

头文件:#include           /* See NOTES */       #include 原型:int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);功能:将套接字与网络信息结构体绑定参数:    sockfd:文件描述符,socket的返回值    addr:网络信息结构体    通用结构体:一般不用        struct sockaddr {               sa_family_t sa_family;               char        sa_data[14];           }    网络信息结构体:                                         stuct sockaddr_in{            sa_family_t sin_family;   //地址族:AF_INET            in_port_t  sin_port;    //网络字节序的端口号            struct in_addr sin_addr  //ip地址                   ---》struct in_addr                    {                        uint32_t s_addr;    //网络字节序的无符号4字节整数Ip地址                                        }                                          }        addrlen:addr的大小返回值:    成功:返回0    失败:返回-1

2.7.3 listen

头文件:#include           /* See NOTES */       #include        原型:int listen(int sockfd, int backlog);功能:将套接字设置为被动监听状态参数:    sockfd:文件描述符,socket的返回值    backlog:允许同时连接的客户端的个数,一般设置为5,10返回值:成功:0失败:-1

2.7.4 accept

头文件:#include           /* See NOTES */       #include              原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);功能:阻塞等待客户端的连接参数:    sockfd:文件描述符,socket的返回值    addr:被填充的网络信息结构体,如果由客户端连接服务器,服务器可以通过这个参数获取客户端的信息    addrlen:addr的大小返回值:成功:返回文件描述符失败:-1

2.7.5 connect

头文件:#include           /* See NOTES */       #include              原型:int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);功能:给服务器发送连接请求参数:    sockfd:文件描述符,socket的返回值    addr:要连接的服务器的网络信息结构体,需要客户端自己填充    addrlen:addr的大小返回值:成功:返回0失败:-1

2.8 TCP服务器

#include          /* See NOTES */#include #include #include #include #include#include #include #include          /* See NOTES */#include int main(int argc, char const *argv[]){    //创建套接字    int sockfd = socket(AF_INET,SOCK_STREAM,0);  //IPV4协议,流式套接字,具体的协议类型    if(-1 == sockfd)    {        perror("socket");        return -1;    }    struct sockaddr_in server_addr;   //保存服务器的信息    memset(&server_addr,0,sizeof(server_addr));    server_addr.sin_family = AF_INET;    server_addr.sin_port = htons(8000);    server_addr.sin_addr.s_addr = inet_addr("192.168.98.147");    //绑定信息    int ret = bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr));    if(-1 == ret)    {        perror("bind");        return -1;    }    //设置监听队列    ret = listen(sockfd,10);    if(-1 == ret)    {        perror("listen");        return -1;    }    printf("等待客户端进行连接...、\n");    struct sockaddr_in Client_addr;    //用于保存客户端的信息    int length = sizeof(Client_addr);    int fd = accept(sockfd,(struct sockaddr *)&Client_addr,&length);    if(-1 == fd)    {        perror("accept");        return -1;    }    printf("接收客户端的连接 %d\n",fd);    char buf[32] = {0};    while(1)    {        ret = recv(fd,buf,sizeof(buf),0);        if(-1 == ret)        {            perror("recv");            return -1;        }        if(strcmp(buf,"bye") == 0)        {            break;        }        printf("%s\n",buf);        memset(buf,0 ,sizeof(buf));    }    close(fd);    close(sockfd);     return 0;}

2.9 TCP客户端

#include          /* See NOTES */#include #include #include #include #include#include #include int main(int argc, char const *argv[]){    //创建套接字    int sockfd = socket(AF_INET,SOCK_STREAM,0);    if(sockfd == -1)    {        perror("socket");        return -1;    }    //向服务器发起连接    struct sockaddr_in server_addr;   //保存服务器的信息    memset(&server_addr,0,sizeof(server_addr));    server_addr.sin_family = AF_INET;    server_addr.sin_port = htons(8000);    server_addr.sin_addr.s_addr = inet_addr("192.168.98.147");    int ret = connect(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr));    if(-1 == ret)    {        perror("connect");        return -1;    }    char buf[32] = {0};    while(1)    {        scanf("%s",buf);        ret = send(sockfd,buf,strlen(buf),0);        if(-1 == ret)        {            perror("send");            return -1;        }        if(strcmp(buf,"bye") == 0)        {            break;        }        memset(buf,0,sizeof(buf));    }    close(sockfd);    return 0;}

2.10 TCP并发服务器

#include          /* See NOTES */#include #include #include #include #include#include #include #include          /* See NOTES */#include #include void * ClientHandler(void *arg){    int ret;    int fd = *(int *)arg;    char buf[32] = {0};    pthread_detach(pthread_self());    //线程结束,自动释放资源    while(1)    {        ret = recv(fd,buf,sizeof(buf),0);        if(-1 == ret)        {            perror("recv");            return (void *)-1;        }        else if(0 == ret)        {            break;   //客户端异常退出        }        if(strcmp(buf,"bye") == 0)        {            break;        }        printf("接收%d客户端 %s\n",fd,buf);        memset(buf,0 ,sizeof(buf));    }    printf("%d 客户端退出!\n",fd);    close(fd);}int main(int argc, char const *argv[]){    //创建套接字    int sockfd = socket(AF_INET,SOCK_STREAM,0);  //IPV4协议,流式套接字,具体的协议类型    if(-1 == sockfd)    {        perror("socket");        return -1;    }    struct sockaddr_in server_addr;   //保存服务器的信息    memset(&server_addr,0,sizeof(server_addr));    server_addr.sin_family = AF_INET;    server_addr.sin_port = htons(8000);    server_addr.sin_addr.s_addr = inet_addr("192.168.98.147");    //绑定信息    int ret = bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr));    if(-1 == ret)    {        perror("bind");        return -1;    }    //设置监听队列    ret = listen(sockfd,10);    if(-1 == ret)    {        perror("listen");        return -1;    }    printf("等待客户端进行连接...、\n");    struct sockaddr_in Client_addr;    //用于保存客户端的信息    int length = sizeof(Client_addr);        while(1)    {        int fd = accept(sockfd,(struct sockaddr *)&Client_addr,&length);        if(-1 == fd)        {            perror("accept");            return -1;        }        printf("接收客户端的连接 %d\n",fd);        //为每一个客户端创建新的线程        pthread_t tid;        ret = pthread_create(&tid,NULL,ClientHandler,&fd);        if(ret != 0)        {            perror("pthread_create");            return -1;        }    }    close(sockfd);     return 0;}

#!/bin/bashfor ((i=0;i<100;i++))do./4-Tcp客户端 &sleep 0.1done

练习:实现客户端下载服务器所在目录文件

客户端发送要下载的文件名给服务器服务器判断文件是否存在,将结果告知客户端如果文件存在,服务器读取文件内容,并发送给客户端客户端收到文件内容并写入指定的文件

2.11 UDP 网络编程

服务器:

创建套接字 socket

填充服务器网络信息结构体

将套接字和网络信息结构体绑定bind

进行通信 recvfrom /sendto()

客户端:

创建套接字 socket

填充网络信息结构体

进行通信 recvfrom/sendto

函数接口

1.recvfrom/sendto

------recvfrom头文件:#include        #include 原型:ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,                        struct sockaddr *src_addr, socklen_t *addrlen);功能:接收数据参数:    前四个和recv一样    src_addr:源的地址,接收谁的数据,他的信息会自动填充到这个参数    addrlen:src_addr的大小返回值    成功:实际接收的字节数    失败: 返回-1------sendto头文件:#include        #include 原型:ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,                      const struct sockaddr *dest_addr, socklen_t addrlen);功能:接收数据参数:    前四个和send一样    dest_addr:目的地址,需要自己指定    addrlen:dest_addr的大小返回值    成功:发送的字节数    失败: 返回-1

//udp服务器#include #include #include #include #include #include #define ERRLOG(errmsg) do{\                            perror(errmsg);\                            printf("%s - %s - %d\n",__FILE__,__func__,__LINE__);\                            exit(1);\                            }while(0)int main(int argc, char const *argv[]){    int sockfd;    //第一步:创建套接字    if(-1 == (sockfd = socket(AF_INET,SOCK_DGRAM,0)))    {        ERRLOG("socket error");    }        struct sockaddr_in serveraddr,clientaddr;    socklen_t addrlen = sizeof(serveraddr);    //第二步:填充服务器网络信息结构体      serveraddr.sin_family = AF_INET;    serveraddr.sin_addr.s_addr = inet_addr("192.168.98.147");    serveraddr.sin_port = 8888;    //第三步:将套接字与服务器网路信息结构体绑定    int ret = bind(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));    if(ret == -1)    {        ERRLOG("bind");    }    //进行通信    char buf[32] = {0};    while(1)    {NEXT:        if(recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&clientaddr,&addrlen) == -1)        {            ERRLOG("recvfrom");        }        if(strcmp(buf,"bye") == 0)        {            printf("客户端%s-%d退出了\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));            goto NEXT;        }        printf("%s-%d: %s\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port),buf);    }    return 0;}

//udp客户端#include #include #include #include #include #include #define ERRLOG(errmsg) do{\                            perror(errmsg);\                            printf("%s - %s - %d\n",__FILE__,__func__,__LINE__);\                            exit(1);\                            }while(0)int main(int argc, char const *argv[]){    int sockfd;    //第一步:创建套接字    if(-1 == (sockfd = socket(AF_INET,SOCK_DGRAM,0)))    {        ERRLOG("socket error");    }        struct sockaddr_in serveraddr,clientaddr;    socklen_t addrlen = sizeof(serveraddr);    //第二步:填充服务器网络信息结构体      serveraddr.sin_family = AF_INET;    serveraddr.sin_addr.s_addr = inet_addr("192.168.98.147");    serveraddr.sin_port = 8888;    //进行通信    char buf[32] = {0};    while(1)    {        scanf("%s",buf);        if(sendto(sockfd,buf,32,0,(struct sockaddr *)&serveraddr,addrlen) == -1)        {            ERRLOG("sendto");        }        if(strcmp(buf,"bye") == 0)        {            printf("客户端退出了\n");        }        memset(buf,0,sizeof(buf));    }    return 0;}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/569815.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-09
下一篇 2022-04-09

发表评论

登录后才能评论

评论列表(0条)

保存