一 IPC通信之 信号灯集
信号灯集:是在内核空间的信号灯的集合
1.1 信号灯集函数接口
1.semget
头文件:#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> 原型: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 <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> 原型: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 <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> 原型: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 <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> 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 <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> 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 <sys/types.h> /* See NOTES */ #include <sys/socket.h> 原型: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 <sys/types.h> /* See NOTES */ #include <sys/socket.h> 原型: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