- 博客(174)
- 收藏
- 关注
原创 Linux HTTP协议
另一方面,HEAD、GET、OPTIONS、TRACE、PUT和DELETE是等幂的,,即多次连续的、重复的请求和只发送一次该请求具有完全相同的效果。如果服务器处理后续HTTP请求时需要用到前面的HTTP请求的相关信息,客户端必须重传这些信息。那么浏览器需要和web服务器三次握手建立连接后,浏览器才可以向web服务器发送HTTP请求报文,服务器收到请求报文后,向浏览器回复HTTP应答报文。这种方法会影响服务器:服务器可能根据收到的数据动态创建新的资源,也可能更新原有的资源。浏览器与web服务器在。
2023-09-13 13:04:12
488
原创 Linux UDP编程流程
此时客户端代码cli.c执行完了sendto,接下来执行recvfrom的时候就被阻塞住了,因为没有服务器端给客户端回复消息,此时发送的aaaaaa发给本主机的6000端口,但是本主机的6000端口没有被占用,也就是6000端口没有被使用,所以所发送的数据aaaaaa就直接被丢掉了,所以也不会有服务器端给客户端回复消息,客户端就会在recvfrom这个地方阻塞住。从结果可以看出,当服务器端启动之后,可以同时启动多个客户端与客户端通信,但是两个客户端的端口号是不同的。服务器端和客户端没有什么本质上的区别。
2023-09-10 23:32:10
620
原创 Linux TCP和UDP协议
粘包在不同情况下的影响不同,比如是下载文件,则没有影响,发送的多个文件可以一次性收完,但是一些交互情况是有影响的,比如客户端发送一个长方体的长、宽、高,服务器端接收这个长方体的长、宽、高之后再给客户端发送这个长方体的体积,客户端发送长方体的长、宽、高分别是20、10、2,服务器端在接收的时候由于粘包,就会一次性接收20、10、2为20102误以为20102是长方体的长,会一直等待接收长方体的宽和高,客户端也会一直等待接收服务器给它发送长方体的体积,发生了阻塞,这时粘包就产生了不好的影响。
2023-09-10 17:58:52
906
1
原创 Linux 多进程解决客户端与服务器端通信
与多线程相比的不同点:多线程如果其中一个线程操作不当,产生了一个信号,会导致整个进程都终止。对于多进程来讲,是产生的子进程去处理客户端的连接,如果子进程终止了,不会影响到其他进程。创建线程的开销比产生新的子进程的开销要小,多线程可以共享整个进程的资源。每当接受一个新的连接就fork产生一个子进程,让子进程去处理这个连接,父进程只用来接受连接。之所以出现僵死进程是因为在子进程结束之后并没有处理子进程,在Linux系统中处理僵死进程的方法有两种,wait和忽略信号。这次僵死进程就不存在了。
2023-09-02 20:58:17
447
原创 Linux 多线程解决客户端与服务器端通信
比如说客户端通过send向服务器端发送数据,那么这个数据就会被写入发送缓冲区中,只要send返回成功就说明所要发送的数据已经成功写入发送缓冲区中。这一行代码的位置,因为此时第一个客户端没有发送消息,所以客户端执行recv的时候发送阻塞,所以服务器端就没有机会执行accept去接收已完成三次握手的监听队列中与第二个客户端建立的连接,因此服务器端的接收缓冲区此时也接收不到第二个客户端从发送缓冲区发送来的数据,所以第二个客户端在执行recv的时候接收不到服务器端给它回复的消息而被阻塞。
2023-08-24 15:22:55
455
原创 Linux TCP协议——三次握手,四次挥手
TCP协议是可靠的、面向连接的、基于字节流的传输层通信协议。TCP的头部结构:源/目的端口号: 表示数据是从哪个进程来, 到哪个进程去;(tcp是传输层的协议,端与端之间的数据传输,在TCP和UDP协议当中不会体现出IP)32位序号:一次TCP通信(从TCP连接建立到断开)过程中某一个传输方向上的字节流的每个字节的编号。32位确认号:对另一方发送来的TCP报文段的响应,即告知发送端期待发送的下一条序号。其值是收到的TCP报文段的序号值加1。
2023-08-23 19:48:46
2862
2
原创 Linux TCP编程流程
端口是一个16位的整形值,一般0-1024 为知名端口,如HTTP使用的80号端口。创建套接字时要指定使用的服务类型,使用基于TCP协议的流式服务(SOCK_STREAM)。处理存放在 listen 创建的已完成三次握手的队列中的连接。每处理一个连接,则accept()返回该连接对应的套接字描述符。监听队列有两种,一个是存放未完成三次握手的连接,一种是存放已完成三次握手的连接。一般由客户端程序执行,需要指定连接的服务器端的IP地址和端口。TCP 提供的是面向连接的、可靠的、字节流服务。
2023-08-23 12:08:00
711
原创 Linux socket网络编程
主机字节序列分为大端字节序列和小端字节序列,不同的主机采用的字节序列可能不同。大端字节序列是指一个整数的高位字节存储在内存的低地址处,低位字节存储在内存的高地址处。小端字节序列是指整数的高位字节存储在内存的高地址处,低位字节存储在内存的低地址处。所以在网络编程中我们会对sockaddr_in结构体进行操作,使用sockaddr_in来建立所需的信息,最后使用类型转化就可以了。地址族类型通常与协议族类型对应。结构体sockaddr_in它用来处理网络通信的地址,是internet环境下套接字的地址形式。
2023-08-22 19:06:55
330
原创 Linux 计算机网络基础概论
如下图,应用程序A要将数据”hello” 传给网络上另外一台主机上的应用程序 B, 数据“hello”从应用层发送给传输层后,传输层在数据前面加上 tcp 协议或 udp 协议的报头,将整条报文发给网络层,网络层添加自己的IP报头,再将整条数据发送给数据链路层。主机环回地址是用来测试的,每台主机都有这个地址,在测试程序的时候就会用这个地址,127代表本主机,所以发给127的数据是不会离开本主机的,它会从网络的发送缓冲区直接导到接收缓冲区,这个数据不会离开网络。目前最大的互联网就是我们常说的因特网。
2023-08-22 16:48:28
1208
原创 Linux 线程同步——条件变量
从pthread_cond_wait开始执行到其调用线程被放入条件变量的等待队列之间的这段时间内,pthread_cond_signal和pthread_cond_broadcast等函数不会修改条件变量的值。也就是说,当线程在进出条件变量的等待队列的时候是不会去唤醒等待队列中的其他线程的。如果有一个线程正在进入等待队列,这时想要唤醒某个线程时就需要加锁,就会加锁失败,要等正在进入等待队列的线程彻底进去之后解锁,然后才能加锁去唤醒想要唤醒的线程,然后再加锁,然后出等待队列的之后在进行解锁。
2023-08-22 12:14:37
250
原创 Linux 多线程中执行fork的情况
多线程程序fork之后产生的子进程只有一条执行路径,就是子进程所在的执行路径。父进程中有互斥锁,那么父进程中锁的状态是什么,在fork之后产生的子进程中的锁的状态就是什么。如果在多线程程序中父进程中加了锁,在fork之后,子进程中要使用这个锁,那么就需要用到pthread_atfork(),pthread_atfork()的实现思路就是看没有进程用锁的时候,在进行fork去产生子进程,以确保父子进程中锁的状态是清晰的。
2023-08-21 20:08:30
354
原创 Linux 线程安全
在多线程中使用库函数的时候一定要使用线程安全版本,这样才能保证线程安全。线程安全指的就是,多线程程序无论调度顺序如何,都能保证程序的结果是正确的,就说该程序处于线程安全的状态。主要的方法就是线程同步和线程安全函数。
2023-08-21 16:52:44
327
原创 Linux 生产者和消费者问题
由结果可以看出,并不是每个线程每次输出的都是5000,而是会有低于5000的情况,这是因为可能会有两个线程在并行运行的时候同时去访问变量g_count,两个线程拿到的g_count的值是相同的,同时执行g_count++,这样就会导致两个线程并不会把g_count的值分别加两次,属于两个线程同时对g_count加1,相当于g_count只加了一次,就会使我们少一个数字。第二个参数pshared:控制信号量的类型,如果其值为0,就表示整个信号量是当前进程的局部信号量,不让该信号量在多个进程之间共享。
2023-08-20 16:34:30
774
原创 Linux 线程并发运行
其中有两个线程在获取i的值的时候一起获取i的值,这时候它们获取到的i的值都为3,也就是说,有两个线程在同一刻去获取i的值,这一刻i的值为3,这两个线程同时执行输出值为3。这是因为被创建的线程函数中index获取了i的值并第一次输出了i的值,睡眠了1秒,这个时候第二次输出的i的值就是在第一次输出i的值之前index已经获取到的值,所以第二次输出的i的值和第一次输出的i的值是一样的,只是第二次输出i的值的顺序和第一次输出i的值的顺序不一样。并行:两个线程在同一时刻同时执行,需要有两个处理器。
2023-08-20 14:48:12
241
原创 Linux 线程库中的接口介绍
start_routine函数的参数。无参数时设为NULL即可。有参数时输入参数的地址。:事先创建好的pthread_t类型的参数。成功时thread指向的内存单元被设置为新创建线程的线程ID。:是一个无类型指针,指定退出信息。进程中的其他线程可以通过调用pthread_join函数访问到这个指针。等待thread指定的线程退出,线程未退出时,该方法阻塞。:是thread线程向主线程返回的信息,不返回信息,就传空。:用于定制各种不同的线程属性。:是线程的id,就是要等待的线程的id。
2023-08-20 13:30:42
125
原创 Linux 一个简单的多线程程序
一个简单的多线程程序编写一个简单的多线程程序代码如下:运行结果:出现这样的运行结果是因为主函数直接就运行完了,直接5次循环就结束了,线程函数还没有来得及执行,整个进程就已经结束了。因为主函数退出之后系统会自动调用exit来退出整个进程,相当于直接把当前进程结束了,不管有多少条执行路径都随之退出了。由于以上代码的执行结果并不理想,主线程和子线程好像并没有同时运行,修改以上代码,如下图所示:在主线程和子线程每次输出数据之后都睡眠1秒,这时就可以看到,两个进程是同时执行的,至于执行的顺序没有固定
2023-08-20 13:23:47
114
原创 Linux 线程的概念与实现方式
一个进程中有两条或多条执行路径的时候,它们是可以同时执行的,也就是说,一个进程中的多个线程是可以同时执行的。也可以有多个不同的子线程,这样就是一个主线程和多个不同的子线程同时执行,多个子线程做的事情不一样。出现这样的运行结果是因为主函数直接就运行完了,直接5次循环就结束了,线程函数还没有来得及输出,因为主函数退出之后系统会自动调用exit来退出整个进程,相当于直接把当前进程结束了,不管有多少条执行路径都随之退出了。有参数时输入参数的地址。线程是进程内部的一条执行序列或执行路径,一个进程可以包含多条线程。
2023-08-19 20:24:56
312
原创 Linux 进程间通信——消息队列
消息的第一个成员是固定的,它是一个长整型,它代表消息的类型,后面的成员是自己定义的数据。当一个进程去接收消息队列中的消息时可以指定消息的类型,当消息队列中没有所指定的消息的类型,进程就会发生阻塞。msgtype < 0的具体解释:假设消息队列里的消息类型有 1、3、4、5 四种类型的消息,如果msgtype = -4,绝对值是4,那就需要取出消息类型小于等于4的所有消息,因此,取出消息的消息类型必须是1、3、4类型。: 消息缓冲区的地址,也就是你要向消息队列中添加的消息,需要满足一定的格式。
2023-08-19 17:43:56
1572
原创 Linux 消息队列的创建与使用
可以看到向这个消息队列中添加了一个消息,这个消息时一个32个字节的字符数组。可以看到消息队列中2个消息变成了1个消息,这是因为进程b把队列中类型为1的第一个消息接收走了。可以看到b进程把消息队列中的消息从队头开始依次接收,直到消息队列中没有消息,再执行b程序时发送阻塞。每运行一次向消息队列发送消息的程序,就会像消息队列发送一次消息。1.a进程创建向消息队列,并向消息队列中发送消息。进程a发送一条消息,进程b读取消息。2.b进程接收消息队列中的消息。
2023-08-19 17:43:35
193
原创 Linux 进程间通信——共享内存
接着执行a程序,因为第一个信号量的初始值为1,执行p操作成功,第一个信号量的值变为0,然后写入数据到共享内存成功,执行第二个信号量的v操作,因为第二个信号量的初始值为0,执行完v操作之后变为1,这时b程序就可以执行对第二个信号量的p操作,执行成功,第二个信号量的值又变为0,b程序读取共享内存的数据成功,然后执行对第一个信号量的v操作,第一个信号量变为1。就这样通过信号量的p、v操作一直循环写入和读取,就实现了a进程输入一次,b进程读取一次,a进程不输入,b进程也不输出。所有进程都可以访问共享内存中的地址。
2023-08-19 11:49:05
406
原创 Linux 进程间通信——信号量
semget()创建或者获取已存在的信号量semget()成功返回信号量的ID, 失败返回-1key:两个进程使用相同的key值,就可以使用同一个信号量nsems:内核维护的是一个信号量集,在新建信号量时,其指定信号量集中信号量的个数semflg可选:IPC_CREAT IPC_EXCL(2)semop()semop()对信号量进行改变,做P操作或者V操作semop()成功返回0,失败返回-1semid:信号量的id//指定信号量集中的信号量下标。
2023-08-18 17:31:58
253
原创 Linux 进程间通信——有名管道和无名管道
管道类型的文件是存放在内存中的,关机之后管道在内存中分配的空间也就没有了,只在进程临时通信的时候使用,管道文件的打开必须至少有一个进程在读文件并且有一个进程在写文件。同理,只执行write文件向管道文件写入数据时,进程也会发生阻塞,这个阻塞同样也是在write.c文件中open打开管道文件的位置发生的。对于管道文件来说,如果写入管道文件的程序关闭了,那么读管道文件的程序就会返回0,解除阻塞;创建的管道文件其实是在内存中分配了一块空间,向管道中写入的数据实际上写入了内存,所以管道文件的大小永远为0。
2023-08-18 13:08:44
525
原创 Linux SIGCHLD信号
实际上就是忽略了子进程的信号SIGCHLD,就相当于间接的告诉内核不想知道子进程的退出码,所以子进程结束之后,直接就将子进程消灭掉,不需要保留子进程的PCB去获取它的退出码。可以看到在子进程结束之后,将SIGCHLD信号发送给了父进程,然后输出SIGCHLD信号的代号17。可以看到子进程结束后并没有变成僵死进程,而是直接消失了。可以看到子进程结束之后直接消失,并没有产生僵死进程。在Unix系统上不可行,仅在Linux系统上可行。
2023-08-17 17:09:14
137
原创 Linux 修改信号的响应方式
修改信号的响应方式要用到方法signal()。需要引用头文件signal.h。signal()的原型:typedef重命名了一个函数指针的类型,这个指针的类型为指向一个参数为int返回值为void的函数的指针。这个函数指针作为signal的返回值,也作为为signal的第二个参数,所以可以传入一个函数指针,即传入函数的地址,也就是函数名;signal第一个参数信号的代号,是整数值,所以是int型。
2023-08-17 16:02:03
147
原创 Linux 发送信号
发送信号的kill函数的操作实际上是系统调用。语法形式:kill函数把参数sig给定的信号发送给由参数pid给出的进程号所指定的进程,成功时它返回0,失败则返回-1。
2023-08-17 15:59:19
298
原创 Linux 信号的基本概念
信号的值在系统源码中的定义如下,它们都以SIG开头:(1)连接挂断(2)终端中断,键盘按下Ctrl+c时,会产生该信号(3)终端退出(4)*非法指令(5)由断点指令或其它陷阱(trap)指令产生(6)调用abort函数生成的信号(7)建立CORE文件,执行I/O自陷(8)建立CORE文件,总线错误(9)建立CORE文件,浮点异常(10)终止进程,杀死进程,该信号的响应方式不允许改变(11)终止进程,用户定义信号1(12)建立CORE文件,段非法错误(13)
2023-08-17 14:50:05
676
原创 Linux 编写一个简单的bash
由结果可以看到,子进程的pid为6889,fork之后就有两个进程,其中一个是父进程main,父进程的pid为6888,另外一个就是子进程,子进程已经被替换成了ps进程。这个过程也就相当于fork把当前的进程main复制了一份,然后将复制了的那一份替换成了ps进程。这就相当于bash进程通过fork把自己复制了一份,产生一个子进程,然后把子进程替换成ps进程,只是过程被忽略掉了。【例】将当前进程复制一份,产生一个子进程,将该子进程替换为ps进程。【例】自己写一个bash进程。
2023-08-16 20:42:06
131
原创 Linux fork 和 exec 联合使用创建一个全新的进程
先fork,使系统中多出一个进程,默认情况下,fork之后,父进程和子进程的代码都一样,子进程是父进程的一个副本,那么把整个副本替换掉, 不会影响父进程,这样就产生了一个全新的进程。这样做的原因是,fork有一个特点,它会把父进程的信息继承给子进程,然后exec进行替换的时候把需要的信息留下,不需要的信息替换掉就可以了,如果是直接创建一个进程,有些信息需要填充,不像复制把父进程的资源复制了一份给了子进程。这个过程也就相当于fork把当前的进程main复制了一份,然后将复制了的那一份替换成了ps进程。
2023-08-16 20:39:31
384
原创 Linux 进程替换
先fork,使系统中多出一个进程,默认情况下,fork之后,父进程和子进程的代码都一样,子进程是父进程的一个副本,那么把整个副本替换掉, 不会影响父进程,这样就产生了一个全新的进程。这样做的原因是,fork有一个特点,它会把父进程的信息继承给子进程,然后exec进行替换的时候把需要的信息留下,不需要的信息替换掉就可以了,如果是直接创建一个进程,有些信息需要填充,不像复制把父进程的资源复制了一份给了子进程。所以可以得出结论,替换的是进程的实体,在替换之后pid是不发生变化的。替换之后,main程序就没有了。
2023-08-16 19:53:45
589
原创 Linux fork和文件操作
通过运行结果可以发现,父进程如果读走了a,那么子进程就会从a的后边开始读,读到了b,子进程不会再把a读一遍,父进程也是一样,从b的后边开始读,读到了c,子进程再从c的后边开始读,读到了d。也就是说,父进程和子进程并没有将一个字符反复去读取,读取的时候我们可以发现,父子进程读文件的文件偏移量是共享的。根据结果可以看到,父进程读了字符a,子进程也读了字符a,父进程读b,子进程也读b。明显看出,这一次父子进程读文件的文件偏移量是没有共享的,父进程和子进程各读各的。文件a.txt的内容为:abcdef。
2023-08-16 15:45:23
141
原创 Linux 通过系统调用复制一个文件
可以看到文件newYY.jpy被创建,并且YY.jpg和newYY.jpg的大小一样。无论是字符文件还是二进制文件都可以通过read和write的系统调用来实现复制的操作。也通过把read读到的数据写入一个新文件中这样的方式来复制一个图片文件。通过把read读到的数据写入一个新文件中这样的方式来复制一个文件。以上操作实现了把文件passwd复制了一份为newpasswd。可以看到passwd和newpasswd的大小一样。可以看出两个文件的内容相同。可以通过传参直接复制文件。2.二进制文件的复制。
2023-08-16 14:52:40
361
原创 Linux 操作文件的系统调用
对于进程来讲,启动一个进程会有3个文件会被默认打开,这三个文件分别是标准输入,标准输出,标准错误输出文件,这3个打开文件在PCB中记录着,PCB中有一个文件表,文件表的下标为0代表第一个文件,即标准输入文件,下标为1代表第二个文件,即标准输出文件,下标为2代表第三个文件,即标准错误输出文件。同时我们也可以看到a.txt的文件描述符为3,这是因为文件描述符0,1,2分别表示了操作标准输入,标准输出,标准错误输出文件,已经被占用了。文件描述符:文件描述符是一个整型,其实就是内核中打开的一个文件的id。
2023-08-16 12:09:44
376
原创 Linux 僵死进程
fork复制进程之后,会产生一个进程叫做子进程,被复制的进程就是父进程。不管父进程先结束,还是子进程先结束,对另外一个进程完全没有影响,父进程和子进程是两个不同的进程。
2023-08-15 18:41:47
416
原创 物理地址和逻辑地址
同学分别坐一个椅子,所有的同学所坐的椅子的编号不一样,也就是每一个逻辑地址对应一个物理地址,每一个逻辑地址所对应的物理地址是不一样的。号同学,第二列是同学所坐的椅子的编号。这个表就相当于一个页表,将逻辑地址和物理地址进行一个映射,会记录逻辑地址对应的物理地址是哪一个。假如有一个3000个座位的阶梯教室,这个阶梯教室的每一个椅子都有一个编号,分别是从。有两个30个人的班级去这个教室坐着上课,每个班的学生的编号是。就相当于逻辑地址,所有的同学坐好之后,每个班的。就相当于物理地址,每个班同学的编号。
2023-08-15 15:12:13
218
原创 Linux 进程的地址空间
在Linux中,用malloc申请一块1G的内存空间,不用free释放也可以,不会发生内存泄漏,因为进程终止之后,所申请的内存空间就会被回收,但是当进程运行的时间长时,也是需要用free来释放的。虽然一个进程的地址空间为4G,但是实际上在执行一个程序的时候并不会把4G的内存空间用完,其中代码段和数据段使用几个页面就足够了,而一个页面的内存是4K,所以执行一个程序实际上用到的内存比4G小很多,所以并不是16G的计算机只能运行4个进程。地址空间除了内核使用的1G,剩下的3G实际上能用的内存空间是小于3G的。
2023-08-15 14:54:27
337
原创 Linux 当fork在for循环中的问题
此时,子进程3是由子进程1第二次进入循环复制而来的,所以子进程3中的fork在子进程1第二次进入循环执行fork产生子进程3的时候就已经执行完了,所以子进程3直接执行。子进程2是由父进程第二次进入循环的时候复制而来的,而子进程2中的fork在父进程进入第二次循环执行fork产生子进程2的时候已经执行完了,所以子进程2直接执行。这时子进程1for循环中i的值等于0,进入循环,这里的fork在父进程第一次进入循环执行fork产生子进程1的时候就已经执行完了,所以直接执行。,i的值等于1,符合。
2023-08-14 19:28:15
540
原创 Linux fork()||fork()问题
这时,对于子进程1来说,第一个fork已经执行完了,它的返回值是等于0的,对于“或”的关系来说,表达式不成立,就要看“||”的另一边,所以执行子进程1中。是“或”的关系,第一个fork大于0时表达式就已经成立了,那么后边的fork是不执行的,它没有机会执行,所以直接执行。在父进程中fork的返回值是大于0的,子进程1中fork的返回值是等于0的。中的第一个fork的返回值等于0,第二个fork的返回值大于0,表达式成立,执行。这时有两个进程,且两个进程的第一个fork已经执行完了。
2023-08-14 18:19:53
403
原创 Linux 复制进程fork
假如父进程和子进程两个进程的内容暂时是一样的,现在只修改父进程中其中两个物理内存的值,其它物理内存不做任何修改,那么就把父进程中这两个物理内存的值各复制了一份给了子进程,子进程重新分配两个物理内存用来存放对应的值,接下来对于父进程中不做修改的物理内存,子进程中就不分配物理内存来存放这块物理内存中的值了,而是让子进程直接去使用父进程中没有被修改物理内存中的值,也就是没有被修改的物理内存就不会被复制一份给子进程,而是让父进程和子进程共享同一个物理内存。调用fork函数的进程为父进程,新生成的进程为子进程。
2023-08-14 16:31:51
471
原创 Linux 主函数参数介绍
由结果可以看出,“hello”、“abc”、"123"都是以字符串的形式传给主函数的参数。真正传入的参数是从argv[1]开始,参数的个数则是传入参数的个数加一。由结果可以看出,在没有传参的情况下,会存在1个参数,这个参数就是当前函数的路径和名称。(3) envp 环境变量,传给主函数的也是一个一个的字符串,只不过环境变量有变量的名字和变量的值。(2) argv 参数内容,是char*类型,说明传给主函数的内容是一个一个的字符串。在使用主函数的时候,这里的参数如果不写,主函数也会自动传参的,比较特殊。
2023-08-14 11:18:13
378
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人