博文

目前显示的是 五月, 2025的博文

c语言之Linux网络开发

一、网络编程预备知识 socket IP地址 端口号 字节序 (一)socket 是一个编程接口 是一种特殊的文件描述符 (everything in Unix is a file) 并不仅限于TCP/IP协议 面向连接 (Transmission Control Protocol - TCP/IP) 无连接 (User Datagram Protocol -UDP 和 Inter-network Packet Exchange - IPX) (二)socket类型 1、流式套接字(SOCK_STREAM) 提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复的发送且按发送顺序接收。内设置流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。 2、数据报套接字(SOCK_DGRAM) 提供无连接服务。数据包以独立数据包的形式被发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。 3、原始套接字(SOCK_RAW) 可以对较低层次协议如IP、ICMP直接访问。 (三)socket的位置 (四)IP地址 IP地址是Internet中主机的标识: Internet中的主机要与别的机器通信必须具有一个IP地址 IP地址为32位(IPv4)或者128位(IPv6) 每个数据包都必须携带目的IP地址和源IP地址,路由器依靠此信息为数据包选择路由 表示形式:常用点分形式,如202.38.64.10,最后都会转换为一个32位的无符号整数 (五)端口号 为了区分一台主机接收到的数据包应该转交给哪个进程来进行处理,使用端口号来区别 TCP端口号与UDP端口号独立 端口号一般由IANA (Internet Assigned Numbers Authority) 管理 众所周知端口:1~1023(1~255之间为众所周知端口,256~1023端口通常由UNIX系统占用) 注册端口:1024~49150 动态或私有端口:49151~65535 (六)字节序 不同类型CPU的主机中,内存存储多字节整数序列有两种方法,称为主机字节序(HBO): 小端序(little-endian) - 低序字节存储在低地址 将低字节存储在起始地址,称为“Little-Endi...

c语言之Linux网络开发

一、网络编程预备知识 socket IP地址 端口号 字节序 (一)socket 是一个编程接口 是一种特殊的文件描述符 (everything in Unix is a file) 并不仅限于TCP/IP协议 面向连接 (Transmission Control Protocol - TCP/IP) 无连接 (User Datagram Protocol -UDP 和 Inter-network Packet Exchange - IPX) (二)socket类型 1、流式套接字(SOCK_STREAM) 提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复的发送且按发送顺序接收。内设置流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。 2、数据报套接字(SOCK_DGRAM) 提供无连接服务。数据包以独立数据包的形式被发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。 3、原始套接字(SOCK_RAW) 可以对较低层次协议如IP、ICMP直接访问。 (三)socket的位置 (四)IP地址 IP地址是Internet中主机的标识: Internet中的主机要与别的机器通信必须具有一个IP地址 IP地址为32位(IPv4)或者128位(IPv6) 每个数据包都必须携带目的IP地址和源IP地址,路由器依靠此信息为数据包选择路由 表示形式:常用点分形式,如202.38.64.10,最后都会转换为一个32位的无符号整数 (五)端口号 为了区分一台主机接收到的数据包应该转交给哪个进程来进行处理,使用端口号来区别 TCP端口号与UDP端口号独立 端口号一般由IANA (Internet Assigned Numbers Authority) 管理 众所周知端口:1~1023(1~255之间为众所周知端口,256~1023端口通常由UNIX系统占用) 注册端口:1024~49150 动态或私有端口:49151~65535 (六)字节序 不同类型CPU的主机中,内存存储多字节整数序列有两种方法,称为主机字节序(HBO): 小端序(little-endian) - 低序字节存储在低地址 将低字节存储在起始地址,称为“Little-Endi...

c语言之信号机制

一、什么是信号 1、概念 信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式 ,所有信号的产生及处理全部都是由内核完成的。 2、信号的产生 按键产生 系统调用函数产生(比如raise, kill) 硬件异常 命令行产生 (kill) 软件条件(比如被0除,访问非法内存等) 3、信号处理方式 缺省方式 忽略信号 捕捉信号 常用信号 : 信号名 含义 默认操作 SIGHUP 该信号在用户终端关闭时产生,通常是发给和该 终端关联的会话内的所有进程 终止 SIGINT 该信号在用户键入INTR字符(Ctrl-C)时产生,内 核发送此信号送到当前终端的所有前台进程 终止 SIGQUIT 该信号和SIGINT类似,但由QUIT字符(通常是 Ctrl-)来产生 终止 SIGILL 该信号在一个进程企图执行一条非法指令时产生 终止 SIGSEV 该信号在非法访问内存时产生,如野指针、缓 冲区溢出 终止 SIGPIPE 当进程往一个没有读端的管道中写入时产生,代 表“管道断裂” 终止 信号名 含义 默认操作 SIGKILL 该信号用来结束进程,并且不能被捕捉和忽略 终止 SIGSTOP 该信号用于暂停进程,并且不能被捕捉和忽略 暂停进程 SIGTSTP 该信号用于暂停进程,用户可键入SUSP字符( 通常是Ctrl-Z)发出这个信号 暂停进程 SIGCONT 该信号让进程进入运行态 继续运行 SIGALRM 该信号用于通知进程定时器时间已到 终止 SIGUSR1/2 该信号保留给用户程序使用 终止 SIGCHLD 是子进程状态改变发给父进程的。 忽略 信号命令 : kill [-signal] pid killall [-u user | prog] kill -l 查看信号数字编号 信号函数 : int kill(pid_t pid, int signum) 功能:发送信号 参数 pid: > 0:发送信号给指定进程 = 0:发送信号给跟调用kill函数的那个进程处于同一进程组的进程。 < -1: 取绝对值,发送信号给该绝对值所对应的进程组的所有组员。 = -1:发送信号给,有权限发送的所有进程。 si...

c语言之进程间通信

一、进程间通信的方式 进程间通信就是进程和进程之间交换信息。 1、常用通信方式 无名管道(pipe) 有名管道 (fifo) 信号(signal) 共享内存(mmap) 套接字(socket) 2、过时的IPC通信方式 System V IPC 共享内存(share memory) 消息队列(message queue) 信号灯集(semaphore set) 二、无名管道 1、原理 int pipe(int pfd[2]); 成功:0;失败:-1,设置errno pfd[0] 为读描述符 pfd[1] 为写描述符 2、注意事项 只能用于亲缘关系的进程间通信(父子进程,兄弟进程) 管道通信是单工的,一端读,一端写(程序实现设计好)。 数据自己读不能自己写 管道可以用于大于2个进程共享 3、读写特性 读管道 管道中有数据,read返回实际读到的字节数 管道中无数据 管道写端被全部关闭,read返回0 (好像读到文件结尾) 写端没有全部被关闭,read阻塞等待(不久的将来可能有数据递达,此时会让出cpu) 写管道 管道读端全部被关闭, 进程异常终止(也可使用捕捉SIGPIPE信号,使进程不终止) 管道读端没有全部关闭 管道已满,write阻塞。(管道大小64K) 管道未满,write将数据写入,并返回实际写入的字节数 三、有名管道(命名管道) 1、创建管道 #include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *filename, mode_t mode); open(const char *path, O_RDONLY);//1 open(const char *path, O_RDONLY | O_NONBLOCK);//2 open(const char *path, O_WRONLY);//3 open(const char *path, O_WRONLY | O_NONBLOCK);//4 2、特点 有名管道可以使非亲缘的两个进程互相通信 通过路径名来操作,在文件系统中可见,但内容存放在内存中 文件IO来操...

c语言之线程

一、线程概念 进程有独立的地址空间,Linux为每个进程创建 task_struct ,每个进程都参与内核调度,互不影响,但是进程在切换时系统开销大,所以很多操作系统引入了轻量级进程LWP,同一进程中的线程共享相同地址空间,Linux不区分进程、线程。 线程特点 : 通常线程指的是共享相同地址空间的多个任务 使用多线程的好处 大大提高了任务切换的效率 避免了额外的TLB & cache的刷新 线程共享资源 : 一个进程中的多个线程共享以下资源: 可执行的指令 静态数据 进程中打开的文件描述符 当前工作目录 用户ID 用户组ID 线程私有资源 : 每个线程私有的资源包括: 线程ID (TID) PC(程序计数器)和相关寄存器 堆栈 错误号 (errno) 优先级 执行状态和属性 二、线程创建 1、Linux线程库 pthread线程库中提供了如下基本操作 : 创建线程 回收线程 结束线程 同步和互斥机制 : 信号量 互斥锁 2、线程创建– pthread_create #include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*routine)(void *), void *arg); 成功返回0,失败时返回错误码 thread 线程对象 attr 线程属性,NULL代表默认属性 routine 线程执行的函数 arg 传递给routine的参数 ,参数是void * ,注意传递参数格式 单线程创建 : #include <stdio.h> #include <pthread.h> #include <unistd.h> void *testThread(void *arg) { printf("this is thread test, pid=%d, tid=%lu\n", getpid(), pthread_self()); printf("input arg=%d\n",(i...

c语言之进程

一、基本概念 (一)进程含义 1、什么是程序 存放在磁盘上的指令和数据的有序集合(文件) 静态的 2、什么是进程 执行一个程序所分配的资源的总称,进程是程序的一次执行过程,动态的,包括创建、调度、执行和消亡 (二)进程内容 BSS段:BSS段通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称。 数据段:数据段通常是指用来存放程序中已初始化的全局变量的一块内存区域。 代码段:代码段通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。 堆(heap):堆是用于存放进程运行中被动态分配的内存段,当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减) 栈(stack):栈又称堆栈, 是用户存放程序临时创建的局部变量,(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进后出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。 进程控制块(pcb) :进程标识PID、 进程用户进程状态、优先级、文件描述符表 (三)进程类型 交互进程:在shell下启动。以在前台运行,也可以在后台运行 批处理进程:和在终端无关,被提交到一个作业队列中以便顺序执行 守护进程:和终端无关,一直在后台运行 (四)进程状态 运行态:进程正在运行,或者准备运行 等待态:进程在等待一个事件的发生或某种系统资源。可中断、不可中断 停止态:进程被中止,收到信号后可继续运行 死亡态:已终止的进程,但pcb没有被释放 二、进程基础 (一)查看进程信息 ps 查看系统进程快照 top 查看进程动态信息 /proc 查看进程详细信息 ps 命令详细参数: -e:显示所有进程 -l:长格式显示更加详细的信息 -f 全部列出,通常和其他选项联用 表头 含义 ...

c语言之标准IO

一、文件的概念和类型 文件是一组相关数据的有序集合,包含以下类型: 常规文件 r 目录文件 d 字符设备文件 c 块设备文件 b 管道文件 p 套接字文件 s 符号链接文件 l 二、标准IO (一)介绍 标准I/O由ANSI C标准定义,主流操作系统上都实现了C库,标准I/O通过缓冲机制减少系统调用,实现更高的效率。 C库函数适配了各种操作系统的差异,建立在系统调用之上。 (二)流(FILE) 1、介绍 标准IO用一个结构体类型来存放打开的文件的相关信息,标准I/O的所有操作都是围绕FILE来进行,FILE又被称为流(stream),文本流/二进制流。 对于流需要注意的是在Windows和Linux操作系统中换行符的不同: Windows 二进制流: 换行符 ‘\n’ 文本流: 换行符 ‘\r’ ‘\n’ Linux 换行符 ‘\n’ 2、流的缓冲 流的缓冲有三种类型:全缓冲、行缓冲、无缓冲 全缓冲 当流的缓冲区无数据或无空间时才执行实际I/O操作 行缓冲 当在输入和输出中遇到换行符(‘\n’)时,进行I/O操作,当流和一个终端关联时,典型的行缓冲 无缓冲 数据直接写入文件,流不进行缓冲 3、预定义流 标准I/O预定义3个流,程序运行时自动打开,分别为:stdin、stdout、stderr stdin、stdout 默认是行缓冲,stderr没有缓冲 4、代码 代码一 #include <stdio.h> #include <unistd.h> int main(int argc, char *argv[]) { int i = 0; printf("a"); // 没有输出任何内容 while (1) { sleep(1); } return 0; } 只有程序正常结束才会刷新缓存,输出内容 如果加入换行符会进行行刷新,输出内容: ... printf("a\n"); ... 代码二 #include <stdio.h>...

c语言之队列及其实现

一、什么是顺序队列 队列是限制在两端进行插入操作和删除操作的线性表 允许进行存入操作的一端称为“队尾” 允许进行删除操作的一端称为“队头” 当线性表中没有元素时,称为“空队” 特点 :先进先出(FIFO) 二、顺序队列设计 创建队列 :CreateQueue () 清空队列 :ClearQueue (Q) 判断队列空 :EmptyQueue(Q) 判断队列满 :FullQueue(Q) 入队 :EnQueue (Q , x) 出队 :DeQueue(Q) typedef int data_t ; /*定义队列中数据元素的数据类型*/ #define N 64 /*定义队列的容量*/ typedef struct { data_t data[N] ; /*用数组作为队列的储存空间*/ int front, rear ; /*指示队头位置和队尾位置的指针*/ } sequeue_t ; /*顺序队列类型定义*/ front指向队头元素的位置 rear指向队尾元素的下一个位置 在队列操作过程中,为了提高效率,以调整指针代替队列元素的移动,并将数组作为循环队列的操作空间。 为区别空队和满队,满队元素个数比数组元素个数少一个。 三、什么是链式队列 插入操作在队尾进行,删除操作在队头进行,由队头指针和队尾指针控制队列的操作。 typedef int data_t; typedef struct node_t { data_t data ; struct node_t *next; } linknode_t, *linklist_t; typedef struct { linklist_t front, rear; } linkqueue_t; 创建空队列 linkqueue_t *CreateQueue() { linkqueue_t *lq = (linkqueue_t *)malloc(sizeof(linkqueue_t)); lq->front = lq->rear = (linklist_t)malloc(sizeof(linknode_t));...

c语言之栈及其实现

一、什么是栈 栈是限制在一端进行插入操作和删除操作的线性表(俗称堆栈),允许进行操作的一端称为“栈顶”,另一固定端称为“栈底”,当栈中没有元素时称为“空栈”。特点 :后进先出(LIFO)。   二、顺序栈 它是顺序表的一种,具有顺序表同样的存储结构,由数组定义,配合用数组下标表示的栈顶指针top(相对指针)完成各种操作。 typedef int data_t ; /*定义栈中数据元素的数据类型*/ typedef struct { data_t *data ; /*用指针指向栈的存储空间*/ int maxlen; /*当前栈的最大元素个数*/ int top ; /*指示栈顶位置(数组下标)的变量*/ } sqstack; /*顺序栈类型定义*/ 创建栈 sqstack *stack_create (int len) { sqstack *ss; ss = (seqstack *)malloc(sizeof(sqstack)); ss->data = (data_t *)malloc(sizeof(data_t) * len); ss->top = -1; ss->maxlen = len; return ss; } 清空栈 stack _clear(sqstack *s) { s-> top = -1 ; } 判断栈是否空 int stack_empty (sqstack *s) { return (s->top == -1 ? 1 : 0); } 进栈 void stack_push (sqstack *s , data_t x) { if (s->top = = N - 1){ printf ( “overflow !\n”) ; return ; } else { s->top ++ ; s->data[s->top] = x ; } return ; } 出栈 datatype stack_pop(sqstack *s) { s->top--; return (...

c语言之单链表及其实现

一、链式存储结构 将线性表L=(a0,a1,……,an-1)中各元素分布在存储器的不同存储块,称为结点,通过地址或指针建立元素之间的联系 结点的data域存放数据元素ai,而next域是一个指针,指向ai的直接后继ai+1所在的结点。 设线性表L=(赵,钱,孙,李,周,吴,郑,王),各元素在存储器中的分布如图 :   二、语法描述 结点类型描述: typedef struct node { data_t data; //结点的数据域// struct node *next; //结点的后继指针域// }listnode, *linklist; 说明: listnode A; linklist p = &A; 设p指向链表中结点ai: 获取ai,写作:p->data; 而取ai+1,写作:p->next->data 若指针p的值为NULL,则它不指向任何结点, 此时取p->data或p->next是错误的。 可调用C语言中malloc()函数向系统申请结点的存储空间 linklist p; p = (linklist)malloc(sizeof(listnode)); 则创建一个类型为linklist的结点,且该结点的地址已存入指针变量p中: 三、链表的实现 1、建立单链表 依次读入表L=(a0,.....,an-1)中每一元素ai(假设为整型),若ai≠结束符(-1),则为ai创建一结点,然后插入表尾,最后返回链表的头结点指针H。 设L=(2,4,8,-1),则建表过程如下: 链表的结构是动态形成的,即算法运行前,表结构是不存在的 2、链表查找 1)按序号查找:实现GetLinklist(h, i)运算。 算法思路:从链表的a0起,判断是否为第i结点,若是则返回该结点的指针,否则查找下一结点,依次类推。 2)按值查找(定位):即实现Locate(h, x)。 算法思路:从链表结点a0起,依次判断某结点是否等于x,若是,则返回该结点的地址,若不是,则查找下一结点a1,依次类推。若表中不存在x,则返回NULL。 3、链表插入 即实现InsertLinklist(h,x, i,)。将x插入表中结点ai之前的情况。 算法思路:...

此博客中的热门博文

玩转虚拟机系列之如何搭建虚拟机

玩转虚拟机系列之远程工具

玩转虚拟机系列之如何高效创建虚拟机