回顾:
UC成长之路1
UC成长之路2
UC成长之路3
UC成长之路4
UC成长之路5
UC成长之路6
UC成长之路7
UC成长之路8
UC成长之路9
UC成长之路10
UC成长之路11
一、进程间通讯
-
system v ipc,IPC(internal process communication),进程间通讯
-
消息队列
-
共享内存
-
信号量集(以后讲)
注: 下面统称以上三个为这些对象
-
使用
ipcs
查看这些对象的内容
-
系统要管理这些对象,需要对每一个对象都有一个唯一的编号(id)
- 消息队列 msqid
- 共享内存 shmid
- 信号量集 semid
消息队列
- 需要在用户空间获取一个键值(具有唯一性),使用这个键值获取一个对象
- 获取键值:ftok(3)
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
//功能:将pathname和proj_id转换为system v IPC的键值
//参数
//pathname:指定文件路径
//proj_id:指定一个非0值,使用这个值得低有效8位
//返回值:成功返回key_t类型的值;错误返回-1,errno被设置
eg:使用ftok(3)获取一个键值,验证proj_id低8位有效
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
int main(void)
{
//key_t key = ftok(".", 1);
key_t key = ftok(".", 257);
if(key==-1){
perror("ftok");
return -1;
}
printf("key=%d\n", key);
return 0;
}
- 消息队列:获取消息队列的id,使用
msgget(2)
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
//功能:获取一个消息队列的id
//参数
//key:跟消息队列id绑定的键值,即ftok(3)的返回值
//msgflg:1)IPC_CREAT:消息队列不存在,创建消息队列
//2)IPC_EXCL:如果和IPC_CREAT一起指定,在消息队列存在的情况下报EEXIST错
//3)mode:指定了消息队列的权限
//返回值:成功返回消息队列的id;错误返回-1,errno被设置
eg:使用msgget(2)获取消息队列的id
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int main(void)
{
//獲取鍵值
key_t key = ftok(".", 257);
if(key==-1){
perror("ftok");
return -1;
}
printf("key=0x%x\n", key);
//獲取消息隊列
int msgflg = IPC_CREAT|0644;
int msgid = msgget(key, msgflg);
if(msgid==-1){
perror("msgget");
return -1;
}
printf("msgid=%d\n", msgid);
return 0;
}
- 使用消息队列实现两个进程间的通讯
- 发送消息到消息队列
msgsnd(2)
- 从消息队列获取消息
msgrcv(2)
- 发送消息到消息队列
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
//功能:发送消息到消息队列
//参数
//msqid:指定了接受消息队列的id
//msgp:是一个地址,指向struct msgbuf类型变量的地址
//msgsz:指定了结构体中mtext字段的长度
//msgflg:默认为0阻塞;IPC_NOWAIT非阻塞(详细请看下面的注意)
//返回值:成功返回0;错误返回-1,errno被设置
//注意:如果消息队列中有充足的空间接收消息,放入消息队列后立即返回;
//如果消息队列中没有充足的空间接收信息,默认阻塞。可以修改msgflg参数
//中包含IPC_NOWAIT,使得进程步阻塞,立即返回,报错。
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
//功能:从消息队列获取消息
//参数
//msqid:指定了消息队列的id,从这个消息队列获取消息
//msgp:存放消息的缓冲首地址
//msgsz:指定了msgp参数指定的结构体中mtext字段的最大值
//msgtyp:指定了请求消息的类型
//msgflg:IPC_NOWAIT 非阻塞 (还有其它的宏,使用man 2 msgsnd查看)
//返回值:成功返回从消息队列中获取的字节数;错误返回-1,errno被设置
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
eg:pa.c创建消息队列,并向消息队列发送一个消息,pb.c获取消息队列id
pa.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
//caller defined
typedef struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
}msgbuf_t;
int main(void)
{
msgbuf_t mb;
//獲取鍵值
key_t key = ftok(".", 257);
if(key==-1){
perror("ftok");
return -1;
}
printf("key=0x%x\n", key);
//獲取消息隊列
int msgflg = IPC_CREAT|0644;
int msgid = msgget(key, msgflg);
if(msgid==-1){
perror("msgget");
return -1;
}
printf("msgid=%d\n", msgid);
//初始化sturct中的成員
mb.mtype=3;//mtype>0就行
strcpy(mb.mtext, "this is a test...\n");
//向消息隊列中發送消息
int msg = msgsnd(msgid, &mb, strlen(mb.mtext), 0);
if(msg==-1){
perror("msgsnd");
return -1;
}
return 0;
}
pb.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
//caller defined
typedef struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
}msgbuf_t;
int main(void)
{
msgbuf_t mb;//存儲獲取到的消息隊列的內容
//獲取鍵值
key_t key = ftok(".", 257);
if(key==-1){
perror("ftok");
return -1;
}
printf("key=0x%x\n", key);
//獲取消息隊列
int msgflg = IPC_CREAT|0644;
int msgid = msgget(key, msgflg);
if(msgid==-1){
perror("msgget");
return -1;
}
printf("msgid=%d\n", msgid);
memset(mb.mtext,0,128);//防止不初始化的空间有不确定值
//從消息隊列中讀取消息
ssize_t rcv = msgrcv(msgid, &mb, 128, mb.mtype, 0);
if(rcv==-1){
perror("msgrcv");
return -1;
}
printf("%s", mb.mtext);
return 0;
}
共享内存:
- 获取共享内存的id,使用
shmget(2)
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
//功能:分配一个共享内存段,并获取这个共享内存段的id
//参数
//key:ftok(3)的返回值
//size:指定了共享内存段的大小
//shmflg:1)IPC_CREAT:共享内存段不存在,创建共享内存段。
//2)IPC_EXCL:
//mode:指定了共享内存段的权限
//返回值:成功返回共享内存段的id;错误返回-1,errno被设置
- shmat(2), shmdt(2)
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
//功能:将共享内存段关联到进程的地址空间
//参数
//shmid;指定了要关联的共享内存端的id
//shmaddr:指定了进程中的关联地址。如果为NULL由内核选择未使用的地址
//shmflg:SHM_RDONLY表明共享内存段只读;为0共享内存段可读可写
//返回值:成功返回关联内存段的地址;错误返回 (void*) -1, errno被设置
int shmdt(const void *shmaddr);
//功能:解除共享内存段和进程的关联
//参数
//shmaddr:指定了共享内存段关联到进程的地址,即shmat(2)的返回值
//返回值:成功返回0,错误返回-1,errno被设置
eg:使用共享内存段实现进程间的通讯
- shma.c
创建共享内存段,将共享内存段关联到的地址空间,然后向内存端中写入字符串“hello beijing”
- shmb.c
获取共享内存段的id,从共享内存段中读出字符串,并将字符串输出到显示器
shma.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>
#include <sys/shm.h>
int main(void)
{
//獲取鍵值
key_t key = ftok(".", 14);
if(key==-1){
perror("ftok");
return -1;
}
printf("key=0x%x\n", key);
//獲取共享內存段的id
int shmid = shmget(key, 1024, IPC_CREAT|0664);
if(shmid==-1){
perror("shmget");
return -1;
}
//將共享內存段關聯到進程的地址空間
void* p = shmat(shmid, NULL, 0);
if(p==(void *)-1){
perror("shmat");
return -1;
}
//操作共享內存段
strcpy(p, "hello beijing");
getchar();
//解除共享內存段和進程的關聯
shmdt(p);
return 0;
}
shmb.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>
#include <sys/shm.h>
int main(void)
{
//獲取鍵值
key_t key = ftok(".", 14);
if(key==-1){
perror("ftok");
return -1;
}
printf("key=0x%x\n", key);
//獲取共享內存段的id
int shmid = shmget(key, 1024, IPC_CREAT|0664);
if(shmid==-1){
perror("shmget");
return -1;
}
//將共享內存段關聯到進程的地址空間
void* p = shmat(shmid, NULL, 0);
if(p==(void *)-1){
perror("shmat");
return -1;
}
//從共享內存段獲取數據v,將數據v輸出到顯示器
printf("%s\n", (char *)p);
getchar();
//解除共享內存段和進程的關聯
shmdt(p);
return 0;
}
二、网络的基础
-
服务器端,客户端
-
什么是服务器?通俗的概念:为客户端提供服务的机器,所以服务器就是机器(硬件),提供服务(服务就是软件)。正式的概念:服务器是软件和硬件的结合。
-
行业标准就是协议
-
在计算机网络通讯中采用的是TCP/IP协议簇
-
TCP/IP协议簇分为4层或5层(7层是OSI参考模型,根本就没有实现)
-
4层:应用层,传输层,网络层,链路层
-
5层:应用层,传输层,网络层,链路层,物理层
-
物理层:规定的是电气协议,电器的规格和尺寸
-
链路层:网帧的相关规定
- 同一个局域网内必须相同
- 流行的网帧有两种:
- 以太网卡
- 令牌环网卡
- 网帧由头部、数据体、尾部构成
- 下面以太网帧的格式意义
- 头部:目的地址(mac地址)、源地址、类型(0800,0806,8035)
-
以太网帧的格式
-
以太网数据帧的分用过程图
-
IP报文格式:IP报文分为两个部分:头部、数据体
-
TCP
-
UDP
要将数据包传递给对方,必须知道对方的MAC地址和目的端口号。知道对方的IP地址,由IP地址获取MAC地址,最后发送给对方。
-
补充
- 集线器:只是电流的放大和分流,工作在物理层,第一层数据交换
- 交换机:交换的是网帧,工作在链路层,第二层数据交换
- 路由器:交换的是IP报文,工作在网络层,第三层数据交换
-
一个ip地址的构成如下:网路号+主机号
- 网络号找到网段:局域网
- 主机号中不能使用全0或全1
- 全0:代表网段地址
- 全1:代表本局域网的广播地址
-
给定一个ip地址,需要知道这个ip地址的网络号和主机号,为获取IP地址的网络号,可以通过子网掩码获取网络号
eg:192.168.1.130/24
192.16.1.139/255.255.255.0所以网络号是192.16.1.0
-
127.0.0.1环回地址,测试本机的网络设备是否正常。
-
网络上的每台机器都有两个表:路由表和arp表
-
sudo route
查看路由表 -
sudo arp -a
查看arp表 -
ping 目标地址
测试两台机器是否可以同行