有名信号量
1.创建:
semget
int semget(key_t key, int nsems, int semflg);
功能:创建一组信号量
参数:key:IPC对像的名字
nsems:信号量的数量
semflg:IPC_CREAT
返回值:成功返回信号量ID
失败返回-1
2.销毁
semctl
int semctl(int semid, int semnum, int cmd, ...);
功能:向信号灯发送命令
参数:semid:信号等的ID
semnum:具体操作信灯的编号
cmd: IPC_RMID 删除信号灯
SETVAL 设置信号量的值
返回值:成功返回0;失败返回-1;
初始化:
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) */
};
3.申请信号量
4.释放信号量
semop
int semop(int semid, struct sembuf *sops, size_t nsops);
功能:对信号量完成操作
参数:semid:信号灯的ID
sops:信号量操作的数组的首地址
nsops:数组元素的个数
返回值:成功返回0;失败返回-1;
unsigned short sem_num; /* semaphore number */ 操作信号量的下标
short sem_op; /* semaphore operation */ 具体对信号量的操作(申请:-1 释放:+1)
short sem_flg; /* operation flags */ SEM_UNDO
write.c
#include "head.h"
int main(void)
{
key_t key;
int shmid = 0;
char *p = NULL;
int semid = 0;
int val[2] = {0, 1};
key = ftok(".", 'a'); //生成一个key值
if (key == -1)
{
perror("fail to ftok");
return -1;
}
semid = semget(key, 2, IPC_CREAT | 0664); //通过key值创建一组信号量
if (semid == -1)
{
perror("fail to semget");
return -1;
}
init_sem(semid, val, 2); //封装函数,对两组信号量初始化
shmid = shmget(key, 4096, IPC_CREAT | 0664); //根据这个key值创建一个共享内存空间
if (shmid == -1)
{
perror("fail to shmget");
return -1;
}
p = (char *)shmat(shmid, NULL, 0); //将地址p用射到共享内存空间中
if (p == NULL)
{
perror("fail to shmat");
return -1;
}
while(1)
{
sem_p(semid, 1); //封装函数,释放写信号量
gets(p); //像这个内存空间中写入数据
sem_v(semid, 0); //封装函数,申请读信号量
if (!strcmp(p,".quit"))
{
break;
}
}
shmdt(p); //解除映射
shmctl(shmid, IPC_RMID, NULL); //删除共享内存空间
return 0;
}
read.c
#include "head.h"
int main(void)
{
key_t key;
int shmid = 0;
char *p = NULL;
int semid = 0;
int val[2] = {0, 1};
key = ftok(".", 'a'); //创建一个key值
if (key == -1)
{
perror("fail to ftok");
return -1;
}
semid = semget(key, 2, IPC_CREAT | 0664); //通过key值创建一组信号量
if (semid == -1)
{
perror("fail to semget");
return -1;
}
init_sem(semid, val, 2); //封装函数,对两组信号量初始化
shmid = shmget(key, 4096, IPC_CREAT | 0664); //根据这个key值创建一个共享内存空间
if (shmid == -1)
{
perror("fail to shmget");
return -1;
}
p = (char *)shmat(shmid, NULL, 0); //将地址p映射到共享内存空间中
if (p == NULL)
{
perror("fail to shmat");
return -1;
}
while(1)
{
sem_p(semid, 0); //封装函数,申请以个读信号量
printf("p = %s\n",p); //打印内存空间中的数据
if (!strcmp(p,".quit"))
{
break;
}
sem_v(semid, 1); //封装函数,释放一个写信号量
}
shmdt(p); //解除映射
shmctl(shmid, IPC_RMID, NULL); //删除共享内存空间
return 0;
}
sem.c
#include "head.h"
#if 0
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
#endif //这个共用体应放在头文件中
/*对信号等的灯的信号量进行初始化*/
int init_sem(int semid, int *parray, int len)
{
union semun myun;
int i = 0;
int ret = 0;
for (i = 0; i < len; ++i)
{
myun.val = parray[i];
ret = semctl(semid, i, SETVAL, myun);
if (ret == -1)
{
perror("fail to semctl");
return -1;
}
}
return 0;
}
/*申请信号灯的信号量*/
int sem_p(int semid, int num)
{
int ret = 0;
struct sembuf mybuf;
mybuf.sem_num = num;
mybuf.sem_op = -1;
mybuf.sem_flg = SEM_UNDO;
ret = semop(semid, &mybuf, 1);
if (ret == -1)
{
perror("fail to semop");
return-1;
}
return 0;
}
/*释放信号灯的信号量*/
int sem_v(int semid, int num)
{
int ret = 0;
struct sembuf mybuf;
mybuf.sem_num = num;
mybuf.sem_op = +1;
mybuf.sem_flg = SEM_UNDO;
ret = semop(semid, &mybuf, 1);
if (ret == -1)
{
perror("fail to semop");
return-1;
}
return 0;
}
网络
网络:
数据传输、数据共享
1.网络协议模型:
OSI协议模型(分层模型、下一层为上一层提供服务)
应用层:实际发送的数据
表示层:发送的数据是否要加密
会话层:是否建立会话链接
传输层:数据传输的方式(数据报、流式)
网络层:数据的路由(如何从一个局域网到达另一个局域网) 依赖于IP地址
数据链路层:局域网下如何通信
物理层:物理介质的链接
TCP/IP协议模型
应用层:决定传输的数据
传输层:决定传输的法方式
网络层:数据如何从一台主机到达另一台主机
网络接口层:物理介质的链接
应用层:
HTTP 超文本传输协议
HTTPS 加密的超文本传输
FTP 文本传输协议
TFTP 简单文本传输协议
SMTP 邮件传输协议
MQTT
TELNET
传输层:
UDP 用户数据报协议
特点:
1、实现机制简单
2、资源开销小
3、不安全不可靠
TCP 传输控制协议
特点:
1、实现机制复杂(三次挥手)
2、资源开销大
3、安全可靠(四次挥手)
网络层:
IPV4
IP地址:唯一标识网络中一台主机的标号
IP地址:网络位 + 主机位
子网掩码:用来标识IP地址的网络位和主机位
子网掩码是1的部分表示IP地址的网络位
子网掩码是0的部分表示IP地址的主机位
网段号:网络位不变,主机位全为0,表示网段号
广播地址:网络位不变,主机位全为1,表示广播地址
IP地址的类型:
A类
1.0.0.0-126.255.255.255
子网掩码:255.0.0.0
管理超大规模网络
私有IP地址:10.0.0.0 - 10.255.255.255
B类
128.0.0.0-191.255.255.255
子网掩码:255.255.0.0
管理大中性规模网络
私有IP地址:172.16.0.0 - 172.31.255.255
C类
192.0.0.0-223.255.255.255
子网掩码:255.255.255.0
管理中小型规模网络
私有IP地址:192.168.0.0 - 192.168.255.255
D类
224.0.0.0-239.0.0.0
用于组播
E类
240.0.0.0-255.255.255.255
用于实验
2.UDP编程:
socket套接字编程:
1、发端:
1)socket
int socket(int domain, int type, int protocol);
功能:创建一个用来通信的文件描述符
参数:domain:使用的协议族 AF_INET(IPV4协议族)
type:套接字类型
SOCK_STREAM:流式套接字
SOCK_DGRAM:数据报套接字
SOCK_RAW:原始套接字
protocol:协议
默认为0
返回值:成功返回文件描述符;失败返回-1;
2)sendto
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
功能:利用套接字向指定地址发送数据信息
参数:sockfd:套接字的文件描述符
buf:发送数据空间的首地址
len:发送数据的长度
flags:属性默认位0
dest_addr:目的地址信息存放的空间首地址
addrlen:目的地址的长度
返回值:成功返回实际发送的字节数;失败返回-1;
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
/* Internet address. */
struct in_addr {
uint32_t s_addr; /* address in network byte order */
};
3)inet_addr
in_addr_t inet_addr(const char *cp);
功能:将字符串IP地址类型转换成内存IP地址
4)htons
uint16_t htons(uint16_t hostshort);
功能:将本地字节序转换成网络的大端字节序
#include "head.h"
int main(void)
{
int sockfd = 0;
struct sockaddr_in recvaddr;
ssize_t nsize = 0;
char tmpbuff[1024] = {0};
fgets(tmpbuff, sizeof(tmpbuff), stdin);
/* 创建用来通信的UDP套接字 */
sockfd = socket(AF_INET, SOCK_DGRAM, 0); //使用IPV4协议族 和数据报套接字
if (-1 == sockfd)
{
perror("fail to socket");
return -1;
}
/* 对方接收方地址赋值 */
recvaddr.sin_family = AF_INET; //
recvaddr.sin_port = htons(50000); //
recvaddr.sin_addr.s_addr = inet_addr("192.168.149.1"); //
/* 发送信息 */
nsize = sendto(sockfd, tmpbuff, strlen(tmpbuff), 0, (struct sockaddr *)&recvaddr, sizeof(recvaddr)); //
if (-1 == nsize)
{
perror("fail to sendto");
return -1;
}
printf("成功发送%ld字节!\n",nsize);
close(sockfd);
return 0;
}