static修饰局部变量时
修饰全局变量或者函数时
修饰静态成员变量的时候
访问此资源时
记得要在类外初始化
static修饰静态成员函数的时候
Q:什么时候使用静态成员函数
: 当不需要实例化
static语句放在public和private中是等效的
tcp粘包解决方案
tcp是可靠的
完整的服务器端代码:
1 |
|
中特别要注意rbytes = recv(cfd,buffer + total_received,length - total_received,0);
这段代码的意思就是
牢骚
真的不喜欢数据结构啊啊 链表什么的真讨厌啊啊啊啊 made真的恶心
还是先学着后面的吧
并发多进程服务器网络聊天模型
这两天在想, 到底是否学会了, 怎么验证你学会了, 我一直在纠结, 但是昨天早上醒来, 我觉得我可能迄今为止做错了很多事, 比葫芦画瓢? 谁都会, 靠着自己脑中残留的记忆来照着写, 真的是硬实力吗? 我不觉得, 我认为只有自己写出来了, 才算你牛逼。
这两天虽然只写了不多的代码
1.warning的警告要看在哪里警告
环形队列数据读写实现
在此项目中
使用一个信号量 (SEM_MUTEX) 用于共享内存的互斥.
使用两个信号量
SEM_EMPTY = 0,表示目前队列只有0个数据为空
当 SEM_FULL = 0 时,表示目前队列剩余0为满,则生产者进程阻塞
网络编程之字节序转换API
ip字符串转换网络字节序:
1
2
int inet_aton(const char *cp, struct in_addr *inp); [addr to network]
功能:将cp指向的IP字符串转成网络字节inp保存的地址中。
1 | int inet_aton(const char *cp, struct in_addr *inp); [addr to network] |
网络字节序转换IP字符串
1
2
3
4
5
6
7
char *inet_ntoa(struct in_addr in); [network to addr]
功能: 将IP网络字节序转换成IP字符串
参数:
@in IP网络字节序
返回值:
成功返回IP字符串首地址, 失败返回NULL
1 | char *inet_ntoa(struct in_addr in); [network to addr] |
主机字节序转换为网络字节序
1
2
3
4
5
short htons(short data); [host to network short ]
功能: 将short类型的整数转成网络字节序
参数:
@data 序号转换的整数
返回值: 得到的网络字节序
1 | short htons(short data); [host to network short ] |
网络字节序转换为十进制数
1 | int atoi(const char *nptr) |
网络编程之字节符转换API
IP字节符转换为网络
进程
所谓进程
进程与程序的区别
- 程序是存储在磁盘资源中的静态指令集合
没有执行的概念, - 进程是程序的动态过程
包括创建, 凋亡等等,
并发与并行的区别
- 并发是指在同一时间段有多个任务同时执行
由操作系统的调度算法来实现, 比较经典的就是时间片轮转, 。 - 并行是指在多个处理器核心下同时执行任务
比如一个cpu4核心, 那么可以同时在每个核心中执行任务, 也就是可以同时执行四个任务,
进程的地址空间由内核空间和用户空间组成
stack用来存储非静态的局部变量
heap用来存储动态申请的内存
.bss用来存放未初始化的全局变量
.data用来存放初始化过并且值不等于0的全局变量
.rodata用来存放只读的变量
.text用来存放程序的文本段
当用户进程需要通过内核获取资源时,会切换到内核态运行,这时当前进程会使用内核空间的资源
进程的状态
- 运行态
- 睡眠态
可中断的睡眠
可被信号唤醒或者等待事件或者资源就绪:
不可中断的睡眠 只能等待特定的事件或者资源就绪: - 停止态(进程暂停接受某种处理
例如。 gdb调试断点信息处理: )。 - 僵尸态(进程已经结束但是资源未被释放)
进程之间的通信
进程之间的通信方式有:管道,信号,消息队列,共享内存,网络
1.管道
管道
- 无名管道
无名管道用于父子进程之间通讯 而且属于单向通讯, 。
无名管道读端与写端抽象成两个文件进行操作 在无名管道创建成功之后, 则会返回读端与写端的文件描述符.,
创建无名管道
int pipe(int pipefd[2]);
特点:
1.当管道为空时 读管道会阻塞读进程,
2.当管道的写端被关闭了 从管道中读取剩余数据后, read 函数返回 0,
3.管道的大小是有限的,不能让父/子进程同时对管道进行读/写操作 - 有名管道
有名管道是在 文件系统中可见的文件,但是不占用磁盘空间,仍然在内存中,可以通过 mkfifo 命令创建有名管道
有名管道用于 任意进程之间的通讯,当管道为空时,读进程会阻塞.
创建有名管道优缺点1
2
3
4
5
int mkfifo(const char *pathname, mode_t mode);
//pathname : 有名管道路径名
//mode : 有名管道文件访问权限
优点 可以实现任意进程间通信: 操作起来和文件操作一样,
缺点:
1.打开的时候需要读写一起进行否则就会阻塞 管道大小是 4096个字节,
2.半双工的工作模式 如果和多个进程通信则需要创建多个管道,
2.信号
定义
信号是在软件层次上 是一种通知机制,对中断机制的一种模拟
是一种异步通信方式 ,
信号的种类
信号的种类有很多
#define SIGKILL 9
所以我们想杀死进程可以用
kill -9 someprocess
信号的处理流程
1.信号的发送
2.信号的投递和处理
如图中所示
- 忽略(除SIGKILL及SIGSTOP)
- 根据自定义处理函数进行处理
- 执行默认操作
信号的发送
函数
kill()和raise()
信号的接收
函数
pause()//阻塞等待信号
信号处理之用户自定义函数
先了解信号处理时注册到内核的函数
sighandler_t signal(int signum, sighandler_t handler);
其后参数的sighandler_t类型为:
typedef void (*sighandler_t)(int); typedef void (*)(int) sighandler_t;
以下为一个父进程向子进程发信号
1 |
|
子进程退出信号
因为父进程fork子进程后
我们从子进程的退出事件为着手点
我们就利用这点
想法
代码如下
1 |
|
静态库与动态库
静态库
在与文件链接形成可执行文件后
静态库在linux以.a结尾,在windows中以.lib结尾
静态库的制作:
首先需要把file.c编译成file.o:
gcc -c file.c -o file.o
然后把.o文件生成静态库:
1 | ar -rs file.a file.o |
生成静态库之后我们需要把main.c与静态库链接起来生成可执行文件
gcc -I<头文件路径> -L<库的路径> main.c -l<静态库的名字> -o <可执行文件名>
gcc 编译器默认搜索头文件与库文件的路径
/usr/include 为头文件默认路径
/usr/lib 与 /lib 为库的默认路径.
假如你已经把头文件
动态库
与静态库相比显然有着不同的特性
在windows中以.dll文件结尾
当可执行文件调用动态库中的函数时
动态库的制作:
gcc -c file.c -o file.o
然后生成动态库
gcc -shared file.o -o file.so
链接的命令则和静态库的一样
error while loading shared libraries: libadd.so: cannot open shared object file: No such file or directory
这是因为我们没有将动态库加载到内存中
export LD_LIBRARY_PATH=.