![](https://img-blog.csdnimg.cn/20201014180756928.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
C
文章平均质量分 72
str999_cn
这个作者很懒,什么都没留下…
展开
-
用C语言开发一个BT下载软件 (四) ------ 代码实现-3-出错处理模块和运行日志模块
出错处理模块 出错处理模块,主要定义了一些错误类型,以及发生导致程序终止的致命性错误时程序的响应。//bterror.h#ifndef BTERROR_H#define BTERROR_H#define FILE_FD_ERR -1 // 无效的文件描述符#define FILE_READ_ERR -2 // 读文件失败#define FILE原创 2017-12-30 12:14:09 · 718 阅读 · 0 评论 -
C语言里的多进程(用fork函数实现)
创建进程有两种方式,一是由操作系统创建;二是由父进程创建。操作系统创建的进程,它们之间是平等的,一般不存在资源继承关系。而由父进程创建的进程(子进程),它们和父进程存在隶属关系。子进程又可以创建进程,形成一个进程家族。 系统调用fork是创建一个新进程的唯一方法。进程调用fork函数就创建了一个子进程。 创建了一个子进程之后,父进程和子进程争夺CPU,抢到CPU者执原创 2017-11-30 10:08:54 · 13276 阅读 · 1 评论 -
用C语言在Linux系统下创建守护进程(Daemon)
守护进程(daemon)是指在后台运行的,没有控制终端与之相连的进程。它独立于控制终端,周期性地执行某种任务。Linux的大多数服务器就是用守护进程的方式实现的。如web服务器进程http等。守护进程在后台运行,类似于Windows中的系统服务。 编写守护进程程序的要点:(1)让程序在后台执行。方法是调用fork()产生一个子进程,然后使父进程退出。(2)调用setsid()原创 2017-12-01 17:15:48 · 14991 阅读 · 1 评论 -
vfork()函数和fork()函数实现子进程的异同
除了fork()函数,还可以用vfork()函数来创建子进程。 (1)使用fork()创建一个子进程时,子进程只是完全复制父进程的资源。子进程独立于父进程,具有良好的并发性。而vfork()创建的子进程,操作系统并不将父进程的地址空间完全复制到子进程,用vfork()创建的子进程共享父进程的地址空间,也就是说,子进程完全运行在父进程的地址空间上。子进程对该地址空间中任何数据的修改同样原创 2017-11-30 18:11:25 · 295 阅读 · 0 评论 -
指针与内存的动态分配(dynamic allocation)
动态分配(dynamic allocation)是程序在运行中取得内存的方法。指针为C的动态分配系统提供必要的支持。全局变量是编译时分配的,而非静态的局部变量使用栈空间,两者都不能在运行中增减。然而,程序在运行中也可能需要数量可变的内存空间。例如,程序可能需要使用动态数据结构,如链表或二叉树。所以程序必须要根据需要分配和释放内存。 C动态分配函数从堆(heap) ------ 系统的原创 2017-11-25 11:28:07 · 2649 阅读 · 0 评论 -
结构体指针作函数的参数
以结构体指针作为参数,在函数中对age成员执行了加1操作。由于使用了指针作为参数,因此在函数内部对age值做的修改,使得数组的实际值也改变了。#includestruct student{ int number; char name[20]; char sex; int age; char addr[30];};//以结构体指针作为参数void print_stru原创 2017-11-22 19:15:37 · 1325 阅读 · 0 评论 -
用C语言开发一个BT下载软件 (四) ------ 代码实现-1-种子文件解析模块
//parse_metafile.h#ifndef PARSE_METAFILE#define PARSE_METAFILE// 保存从种子文件中获取的tracker的URLtypedef struct _Announce_list { char announce[128]; struct _Announce_list *next;} Announce_list;//原创 2017-12-24 13:44:28 · 4022 阅读 · 5 评论 -
指针数组和二级指针
数组元素是指针类型的数组就称为指针数组。指针数组的每一个元素都是指针变量。定义形式:类型名 *数组名[数组长度],如: int *p[10] 二级指针,就是指向指针的指针。#include int main(int argc, char *argv[]){ int a[5]={1,3,5,7,9}; int *p[5],i; int **pp=p;原创 2017-11-21 11:51:02 · 9693 阅读 · 1 评论 -
C语言的指针
char *p:这是定义了一个指向char型变量的指针,p存放的是一个char类型变量的地址,*p是取得指针p所指向的地址存储的值,&是取地址运算符,&c是取得变量c的地址。总结于下: &:取地址运算符。 *:取指针所指向的内存单元的值。 对于程序中的每一个变量,编译程序时都要分配一块内存用于存储该变量的值。例如: cha原创 2017-11-18 00:07:39 · 266 阅读 · 0 评论 -
用C语言开发一个BT下载软件 (三) ------ 系统结构设计
整个系统各个模块功能如下图所示:种子解析:负责解析种子文件,从中获取Tracker服务器的地址,待下载文件的文件名和长度,piece长度,各个piece的hash值。连接Tracker:根据HTTP协议构造获取peer地址的请求,与Tracker建立连接,解析Tracker的回应消息,从而获取各个peer的IP地址和端口号。与peer交换数据:根据peer的IP地址和端口号连接原创 2017-12-24 05:55:44 · 1542 阅读 · 0 评论 -
用C语言开发一个BT下载软件(一) ------ BitTorrent协议 -2
与Tracker交互 完成解析种子文件并从中获取Tracker服务器的URL后,即可开始与Tracker进行交互。交互有2个目的:将自己的下载进度告知给Tracker以便Tracker进行一些相关统计;获取当前下载同一个共享文件的peer的IP地址和端口号。 客户端使用HTTP协议与Tracker通信。通过HTTP GET方法从Tracker获取请求,请求的原创 2017-12-23 15:31:34 · 3564 阅读 · 3 评论 -
用C语言开发一个BT下载软件(一) ------ BitTorrent协议 -1
BitTorrent(简称BT)是一个文件分发协议,每个下载者在下载的同时不断地向其他下载者上传已下载的数据。它是属于一个应用层的协议。 基于BT协议的文件分发系统由以下几个实体构成:一个web服务器一个种子文件一个Tracker服务器一个原始文件提供者一个网络浏览器 若干个下载者 web服务器上保存着种子文件。种子文件又称为元文件或metafile,它保存原创 2017-12-23 13:40:04 · 4403 阅读 · 0 评论 -
C语言的二维数组、及多维数组的降维
二维数组的定义形式:数据类型 标识符[ ] [ ] 第一维一般称为“行”,第二维称为“列”。比如: float array[3][4]。 二维数组的初始化。 1. 将所有数据写在一个大括号内,如: array[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; 数组逐行、逐列顺序地被赋予上述数值。 2.原创 2017-11-17 23:48:22 · 4039 阅读 · 0 评论 -
C语言的一维数组和字符数组
上文介绍的都是基本数据类型(整形、浮点型、字符型等),现在开始接触另外3种复合数据结构:数组、结构体、共用体。 数组和变量一样,也是先定义,后使用。数组定义的形式是类型名、标识符、维数。比如:int a[10],这就定义了一个含有10个整形元素的数组。 可以在定义数组的同时进行初始化,如:int a[]={0,1,2,3,4,5,6,7,8,9};这时就无需指定元素个数。原创 2017-11-17 19:09:07 · 2135 阅读 · 0 评论 -
用fputs()写入,用fgets()读出一个字符串
与putc(),getc()类似,将c替换成s的含义是不单单处理一个字符,而是处理一个字符串。这2个函数的原型是:int fputs(const char *str,FILE *fp);char *fgets(char *str, int length, FILE *fp); 函数fputs()向指定的流写串(由str指定)。出错时,fputs()返回EOF。 下原创 2017-11-27 07:00:45 · 1163 阅读 · 0 评论 -
用C语言实现一个自己的文件拷贝工具
#include #include int main(int argc, char *argv[]){ FILE *in, *out; char ch; if(argc!=3) { printf("You forgot to enter a filename.\n"); exit(1); } //打开源文件 if((in=fopen(argv[1原创 2017-11-27 06:37:40 · 583 阅读 · 0 评论 -
线程同步1 ------ 互斥锁 ------一个更加典型的例子
上一篇博文里,举了一个简单的应用共享锁的例子。本篇博文将介绍一个稍微更加复杂点的例子。 有一个全局变量数组out,包含100个元素,所有元素初始化为0。然后开启2个子线程同时对数组out进行赋值操作。在此过程,应该启用共享锁对赋值代码进行同步。具体代码如下:#include #include pthread_mutex_t number_mutex;//out数组是全局原创 2017-12-04 11:19:54 · 1674 阅读 · 0 评论 -
线程同步2 ------ 条件变量
条件变量是利用线程间共享的全局变量进行同步的一种机制。条件变量宏观上类似if语句,符合条件就能执行某段程序,否则只能等待条件成立。 使用条件变量主要包括2个动作:一个等待使用资源的线程“等待条件变量被设置为真”;另一个线程在使用完资源后“设置条件为真”,这样就可以保证线程间的同步了。那么关键的问题来了,就是要保证条件变量能被正确地修改,条件变量应该得到特殊的保护。实际使用中其实仍然需原创 2017-12-05 21:19:21 · 313 阅读 · 0 评论 -
线程同步2 ------ 用条件变量来解决生产者消费者问题
转载自:http://blog.csdn.net/chen_mama/article/details/47429695在上一篇文章中,我使用了匿名信号量什么是条件变量? 我们可以设想一个场景:线程A需要某个条件成立才能继续执行,否则一直等待下去,而线程B执行过程中使线程的执行条件成立,并且唤醒A。 举个例子,在生产者消费者模型中,消费者如果看到缓冲区为空时,就等待,而生转载 2017-12-06 17:58:19 · 231 阅读 · 0 评论 -
用C语言开发一个BT下载软件 (四) ------ 代码实现-2-位图管理模块的代码实现
//bitfield.h#ifndef BITFIELD_H#define BITFIELD_H//位图结构体typedef struct _Bitmap { unsigned char *bitfield; // 保存位图地址的指针 int bitfield_length; // 位图所占的总字节数 int valid_len原创 2017-12-29 18:49:21 · 885 阅读 · 0 评论 -
用C语言开发一个BT下载软件 (二) ------ 算法和策略
流水线作业 当客户端向peer发送数据请求时(即发送request消息),一次请求多个slice(即在一个数据包中发送多个request消息请求多个slice)。peer发送完一个slice后接着发送下一个slice,从而避免了等待,提高了数据传输的效率。片断(piece)选择算法一旦向某个peer发送对某个piece中的slice请求后,则该piec原创 2017-12-24 05:27:22 · 2337 阅读 · 0 评论 -
用C语言开发一个BT下载软件 (四) ------ 代码实现-5-Peer管理模块
系统为每一个与之建立TCP连接的Peer构造一个Peer结构体。Peer管理模块负责管理由各个Peer节点构成的Peer链表,主要工作是创建节点,添加节点到Peer链表,从Peer链表中删除节点等。//peer.h#ifndef PEER_H#define PEER_H#include #include #include "bitfield.h"#define IN原创 2018-01-04 11:10:03 · 1196 阅读 · 3 评论 -
进程间通信(IPC)4 ------ 共享内存(配合使用信号量进行同步)
共享内存就是能被不同进程共同访问的一块内存。 函数shmget()用以创建一个共享内存,或者访问一个已存在的共享内存。原型如下:#include int shmget(key_t key, size_t size, int shmflg);参数key是由ftok()函数或得的键值。参数size以字节为单位制定内存的大小。创建新的共享内存时,size必须大于0;如果访问一原创 2017-12-18 22:56:58 · 486 阅读 · 0 评论 -
进程间通信(IPC)3 ------ 消息队列 - 2
上文将消息队列中放入了数据,其他进程就可以从中读取消息了。读取消息的函数是msgrcv(),该函数原型为:#include int msgrcv(int msgid, struct msgbuf *msgp, size_t msgsz, long int msgtyp, int msgflg); 相关参数的含义上文已经说明,此处略过。 使用相同的参数PATH_NA原创 2017-12-18 15:10:20 · 216 阅读 · 0 评论 -
进程间通信(IPC)3 ------ 消息队列 - 1
消息队列是一个存放在内核中的消息链表,由消息队列标识符标识。 向消息队列发送消息时,必须组成合理的数据结构。Linux系统定义了一个模板数据结构msgbuf:#include struct msgbuf{ long mtype; char mtext[1];}; mtype字段代表消息类型。mtext字段指消息内容。原创 2017-12-18 14:32:27 · 307 阅读 · 0 评论 -
进程间通信(IPC)2 ------ 有名管道
管道的一个不足之处是没有名字,因此只能在具有亲缘关系的进程之间通信。而“有名管道”与此不同,它提供了一个路径名与之关联,作为一个设备文件存在,即使无亲缘关系的进程之间,只要能访问该路径,也可以通过FIFO进行通信。FIFO总是按照先进先出的原则工作,第一个被写入的数据将首先从管道中读出。 函数原型:#include #include int mkfifo(const char原创 2017-12-18 13:56:32 · 320 阅读 · 0 评论 -
进程间通信(IPC)1 ------ 管道
进程的地址空间是互相独立的,因此进程之间交互数据必须采用专门的通信机制。尤其是在大型的软件系统中,往往需要多个进程互相协作共同完成一个任务,这就需要使用进程间通信(Inter-Process Connection, IPC)编程技术。 管道(Pipe)是两个进程之间进行单向通信的机制,因为它的单向性,所以又称为半双工管道。它主要用于进程间的一些简单通信。数据只能由一个进程原创 2017-12-17 22:44:24 · 218 阅读 · 0 评论 -
用C语言开发一个BT下载软件 (四) ------ 代码实现-4-信号处理模块
在运行过程中,程序会收到一些信号,比如SIGINT、SIGTERM,这些信号的默认动作是立即终止程序。但在终止程序之前,需要首先执行一些善后操作,比如释放动态申请的内存、关闭文件描述符、关闭套接字等。这些善后操作就是在信号处理模块里进行。本模块的头文件是signal_handler.h,源文件是signal_handler.c。//signal_handler.h#ifndef SIGNA原创 2018-01-01 10:00:33 · 625 阅读 · 0 评论 -
定时器信号的用法
#include #include #include #include /*信号处理程序*/void handler_sigtime(int signo){ switch (signo) { case SIGALRM: printf("recv SIGALRM\n"); break; case SIGPROF: printf("recv SIGPROF\n原创 2017-12-17 19:29:24 · 476 阅读 · 0 评论 -
信号的捕获和处理
信号(signal)是一种软件中断,是进程间唯一的异步通信方式。 信号有很多,常见的有:SIGINT:在键盘按下组合键后产生,默认动作为终止进程SIGQUIT:在键盘按下组合键后产生,默认动作为终止进程SIGKILL:无条件终止进程。本信号不能被忽略、处理和阻塞。默认动作为终止进程。它向系统管理员提供了一种可以杀死任何进程的方法SIGALRM:定时器超时,超时的时间由系统原创 2017-12-16 15:34:04 · 5647 阅读 · 0 评论 -
线程同步3 ------ 信号量在不同进程间同步的又一个实例
以下实例通过信号量实现对临界资源的同步访问问题。server程序创建一个信号集,并对信号量循环减1,相当于分配资源。而client在执行时首先检查信号量,如果大于0代表有资源可用,就继续执行。如果信号量小于0代表资源已经分配完毕,进程client退出。server.c//server.c#include #include #define MAX_RESOURCE 5int m原创 2017-12-15 11:23:25 · 358 阅读 · 0 评论 -
线程同步3 ------ 信号量实现进程或者线程之间的同步
基本概念 信号量是一个计数器,常用于处理进程或线程的同步问题,特别是对临界资源访问的同步。临界资源可以简单地理解为在某一时刻只能由一个进程或线程进行操作的资源。信号量的值与相应资源的使用情况有关,当它的值大于0时,表示当前可用资源的数量,当它的值小于0时,其绝对值表示等待使用该资源的进程个数。原创 2017-12-14 15:41:01 · 2757 阅读 · 0 评论 -
线程同步3 ------ Linux进程间通信——使用信号量
这篇文章将讲述别一种进程间通信的机制——信号量。注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物。有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信——使用信号。下面就进入信号量的讲解。一、什么是信号量为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,它可以通过生成并使用令牌来授权,在任一时刻只能有一个执行转载 2017-12-12 14:20:53 · 225 阅读 · 0 评论 -
线程同步2 ------ 条件变量实现“生产者-消费者”续
在上一篇转载博客的基础上,我想实现当生产者结束生产任务后,让消费者线程优雅主动地退出循环结束线程。具体代码修改如下。但是事与愿违,执行结果是,只有消费者线程里的第一个线程,能够主动退出循环结束线程,而其他消费者线程仍然不停地轮询等待。 代码:#include #include #include #include #include #include #include原创 2017-12-06 18:09:13 · 323 阅读 · 0 评论 -
C语言的文件系统
C文件系统由若干互相联系的函数构成,这类函数要求包含头文件。常用的缓冲文件系统函数有: fopen():打开一个文件 fclose():关闭一个文件 putc(),fputc():向文件写一个字符 getc(),fgetc():从文件中读取一个字符 fgets():从文件中读一字串 fputs():原创 2017-11-27 05:17:11 · 8497 阅读 · 0 评论 -
C语言的枚举类型(enumeration)
枚举(enumeration)是一系列命名的整形常量。枚举的例子有,一个星期里每一天的名称,钱币的币值等。如美国硬币币值的枚举定义:enum coin{penny,nickel,dime,quarter,half-dollar,dollar}; 以下代码声明money为枚举类型coin的变量:enum coin money;//使用枚举类型变量money=dime;i原创 2017-11-25 21:00:55 · 2984 阅读 · 0 评论 -
套接字编程4 ------ 动态生成多线程并发扫描服务器端口的实例
本程序使用TCP connect方式对服务器进行端口扫描。 本程序在扫描端口时使用了多线程技术,把要扫描的所有端口平均分配给一些线程,每一个线程负责扫描一部分端口。主线程负责任务分配、启动各个子线程和等待子线程结束。代码如下:// 端口扫描程序,只支持扫描TCP端口#include #include #include #include #include #includ原创 2017-12-22 03:19:58 · 520 阅读 · 0 评论 -
C语言的结构体
C语言中的基本数据类型有:整形、浮点型、字符型,复合数据类型:数组。还有一种构造数据类型,叫“结构体”。 声明结构体的形式: struct 结构体名 { 成员列表 }; 成员列表可以是C语言的任何数据类型,如:整形、浮点型、字符型、数组,指针,结构体、共用原创 2017-11-22 15:34:59 · 221 阅读 · 0 评论 -
C语言有关字符串处理的函数
(1)puts和gets puts将一个字符串输出到屏幕上。gets从终端输入一个字符串到字符数组中。char a[]="Welcome to";char *p="Linux C Program";puts(a);puts(p);(2)strcpy和strncpy #include char *strcpy(char *原创 2017-11-22 14:31:34 · 236 阅读 · 0 评论 -
指向字符串的指针 ------ 字符串指针
(1)用字符数组存放一个字符串 char string[]="Linux C"; printf("%s\n",string); string是一个字符数组名,它同时也是该字符数组的首地址。 (2)用字符串指针来指向字符串 如果不想定义字符数组,就可以只用一个指向字符串的指针,叫“字符串指针”,例如:原创 2017-11-21 21:46:03 · 3588 阅读 · 1 评论