linux应用基础(文件、进程线程、网络)

1.文件流

1.文件IO笔记

1.缓冲分类(笔记)
1.行缓冲
	大小:
	分类:标准输出printf,标准输入scanf
	刷新:\n,程序结束,fflush 
2.全缓冲
	大小:
	分类:文本文件
	刷新:写满,程序结束,fflush 
3.无缓冲	
	标准错误输出流
4.
	无缓存IO read()write()函数,直接从硬盘中读取和写入文件,它们都属于系统调用,只在内核缓存
	有缓存IO(标准IO) fread(), fwrite()函数,它们都属于用户层调用,在内核和用户层都有缓存
2.文件流C库函数(笔记)
1.fopen() 打开成功返回指针,打开失败返回NULL
2.fclose()关闭成功返回0,关闭失败返回EOF

3.fgetc()从流中取一个字符   一个流参数
4.fputc()从流中输出一个字符 一个流参数

5.fgets()从流中取字符串    目标 长度 流
6.fputs()从流中输出字符串  目标 长度 流

7.fprintf()将内容输出到流  流   格式   参数
8.fscanf()获取流中的数据   流   格式   参数 

9.feof()判断是否到达文件结尾   如果到了结尾返回0 未到结尾返回非零值

10.sprintf() 字符数组   格式   参数
11.sscanf()  字符数组   格式   参数

12.rewind()设置文件位置为给定流 stream 的文件的开头。
	void rewind(FILE *stream) 
	//设置文件位置为给定流 stream 的文件的开头。
13.fseek()流位置偏移
	int fseek(FILE *stream, long int offset, int whence)
		stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
		offset -- 这是相对 whence 的偏移量,以字节为单位。
		whence -- 这是表示开始添加偏移 offset 的位置。它一般指定为下列常量之一:
			SEEK_SET	文件的开头
			SEEK_CUR	文件指针的当前位置
		SEEK_END	文件的末尾
14.ftell()返回给定流 stream 的当前文件位置。
	long int ftell(FILE *stream) 
	//返回给定流 stream 的当前文件位置。
		如果发生错误,则返回 -1L,全局变量 errno 被设置为一个正值。

15.fread();
	size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
	//从给定流 stream 读取数据到 ptr 所指向的数组中。
		ptr -- 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
		size -- 这是要读取的每个元素的大小,以字节为单位。
		nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
		stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。
	size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
16.fwrite()

//把 ptr 所指向的数组中的数据写入到给定流 stream 中。
	ptr -- 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
	size -- 这是要读取的每个元素的大小,以字节为单位。
	nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
	stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。

17.fflush();
int fflush(FILE *stream) 
//刷新流 stream 的输出缓冲区。
	成功返回零值。错误则返回 EOF
		stdin  标准输入流 键盘
		stdout 标准输出流 屏幕
		stderr 标准错误流
3.文件流系统函数(笔记)
常用文件IO系统函数

1.open()     2.write     ()3.read()     4.close()      5.lseek()
6.send()     7.recv      ()8.readv()    9.writev()
10.dup()     11.dup2     ()12.umask()   13.unlink()    14.truncate()

1.open()
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
	pathname      文件路径
	flags         文件标志
		O_WRONLY  只读,文件必须存在
		O_RDONLY  只写,文件必须存在
		O_RDWR    读写,文件必须存在
		//可选
		O_CREAT   文件不存在就创建      
		O_TRUNC   文件存在截断为0
		O_APPEND  文件打开追加写
		O_EXCL    如果文件存在且指定O_CREAT,则出错)
	mode_t mode   创建的文件的权限,创建的文件权限=设定的权限-umask
	返回值: 成功返回文件描述符,失败返回-1 

		/*
			r     O_RDONLY
			r+	  O_RDWR
			w     O_WRONLY | O_CREAT | O_TRUNC
			w+    O_WRONLY | O_CREAT | O_TRUNC
			a     O_RDONLY | O_CREAT | O_APPEND
			a+    O_RDWR   | O_CREAT | O_APPEND
		*/
2.write()
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
	fd:文件描述符
	buf:数据缓冲区
	count:读取数据大小
	返回值:文件读完(0),读取的字符(>0),读取失败(-13.read()
#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);
	fd:文件描述符
	buf:数据缓冲区
	count:读取数据大小
	返回值:文件读完(0),读取的字符(>0),读取失败(-14.close()
#include <unistd.h>
int close(int fd);
    fd:文件描述符
	返回值:错误返回-1,正确返回0

5.lseek()
#include <sys/type.h>
#include <unistd.h>
off_t lseek(int  fd,off_t offset,int whence)
	fd:文件描述符
	offset:偏移量
	whence:位置
		SEEK_SET(偏移到offset地方,相对于文件头)
		SEEK_CUR(偏移到当前位置+offset)
		SEEK_END(偏移到文件尾+offset)  
	返回值:返回距离起始位置的偏移量,失败返回-1
	
________________________________________________________________________________________________

6.send()
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int s,const void*buf,size_t len,int flags);
	s
	buf:数据缓冲区
	len
	flags:
		MSG_DONTWAIT	非阻塞,立即返回,不等待
		MSG_ERRQUEUE	错误消息从套接字错误队列中接收
		MSG_OOB	接收外部数据
		MSG_PEEK  	查看数据,不进行数据缓冲区的清空
		MSG_TRUNC	返回所有数据,即使指定的缓冲区过小
		MSG_WAITALL	等待所有消息
7.recv()
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int s,void *buf,size_t len,int flags)
	s
	buf
	len
	flags
		MSG_DONTWAIT	非阻塞,立即返回,不等待
		MSG_ERRQUEUE	错误消息从套接字错误队列中接收
		MSG_OOB	        接收外部数据
		MSG_PEEK  	查看数据,不进行数据缓冲区的清空
		MSG_TRUNC	    返回所有数据,即使指定的缓冲区过小
		MSG_WAITALL	    等待所有消息

8.readv()
#include <sys/uio.h>
ssize_t readv(int s,const struct iovec *vector,int count);


9.writev()
#include <sys/uio.h>
ssize_t writev(int s,const struct iovec *vector,int count);
________________________________________________________________________________________________
10.dup()
#include <unistd.h>
int dup(int oldfd);
	oldfd:旧文件描述符
	返回最小的尚未被使用的文件描述符
	错误返回-1
11.dup2()
int dup2(int oldfd, int newfd);
	oldfd:旧文件描述符
	newfd:新文件描述符
	返回值:如果newfd 已被使用则先关闭
			如果newfd 与 oldfd相同则不关闭oldfd
			错误返回-1
	newfd作为文件描述符与old指向同一文件

12.umask()
#include <sys/types.h>
#include <sys/stat.h>
mode_t umask(mode_t mask);

	umask设置的是权限的补码
	默认情况下的umask值是022
	文件默认权限是644(6-0,6-2,6-2)
	目录默认权限是755(7-0,7-2,7-2)
13.unlink()
#include <unistd.h>
int unlink(const char *pathname)
	pathname:文件路径
	返回值:成功返回0,失败返回 -1
	
	连接数大于1进行减1操作
	连接数为1才会删除文件

14.truncate()
#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
	path:文件路径
	off_t length:截断后的文件长度

2.文件IO函数使用

1.文本复制(代码)
//文本复制
#include <stdio.h>
int main(int argc, char *argv[])
{
	if(argc != 3)
	{
		printf("usage :%s <filename>, <filename>\n", argv[0]);
		return -1;
	}
	FILE *fp1 = fopen(argv[1], "r");
	FILE *fp2 = fopen(argv[2], "w");
	if(fp1 == NULL || fp2 == NULL)
	{
		perror("fopen");
		return 0;
	}
	
	/*
	char ch;
	while(!feof(fp1))
	{
		ch = fgetc(fp1);
		fputc(ch, fp2);
	}
	*/
	char str[128];
	while(!feof(fp1))
	{
		fgets(str,128,fp1);
		fputs(str, fp2);
	}
	fclose(fp1);
	fclose(fp2);
	return 0;
}   
//文本反向复制 ftell fseek
#include <stdio.h>
int main(int argc, char *argv[])
{
	if(argc != 3)
	{
		printf("usage :%s <filename>, <filename>\n", argv[0]);
		return -1;
	}
	FILE *fp1 = fopen(argv[1], "r");
	FILE *fp2 = fopen(argv[2], "w");
	if(fp1 == NULL || fp2 == NULL)
	{
		perror("fopen");
		return 0;
	}
	char ch;
	fseek(fp1,-1, SEEK_END);
	while(1)
	{
		ch = fgetc(fp1);
		fputc(ch, fp2);
		if(ftell(fp1) == 1)
		{
			break;
		}
		fseek(fp1,-2, SEEK_CUR);
	}
	return 0;
}       
2.文件复制(代码)
//文件复制
#include <stdio.h>
int main(void)
{
	FILE *fp1 = fopen("01.jpg", "rb");
	FILE *fp2 = fopen("02.jpg", "wb");
	if(fp1 == NULL || fp2 == NULL)
	{
		perror("fopen");
		return -1;
	}
	char buf[1024];
	
	/*
	int n = fread(buf, sizeof(char), 1024, fp1);
	while(n > 0)
	{
		fwrite(buf, sizeof(char), 1024, fp2);
		n = fread(buf, sizeof(char), 1024, fp1);
	}
	*/
	while(!feof(fp1))
	{
		fread(buf, 1, 1024, fp1);
		fwrite(buf, 1, 1024, fp2);
	}
	fclose(fp1);
	fclose(fp2);
	return 0;
}
3.目录文件相关函数的使用(代码)
//dup dup2
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
	if(argc != 2)
	{
		printf("usage : %s <filename>\n", argv[0]);
		return -1;
	}
	int fd1 = open(argv[1],O_WRONLY | O_CREAT | O_TRUNC ,0666);
	int fd2 = dup(fd1);
	printf("fd1:%d fd2 :%d\n", fd1, fd2);
	
	int fd3 = dup2(fd2, 10);
	printf("fd3:%d\n", fd3);
	
	return 0;
}
/*
暂未写此部分
umask
ulink
truncate
stat
opendir closedir
*/
4.time库使用(代码)
//time库的使用
#include <stdio.h>
#include <time.h>
int main(int argc, char *argv[])
{
	time_t tv;
	time(&tv);
	printf("秒数:%ld\n", tv);
	char *s = ctime(&tv);
	printf("格式化时间:%s", s);	
	struct tm *p;
	p = localtime(&tv);
	printf("年:%d ", p->tm_year+1900);
	printf("月:%d ", p->tm_mon+1);
	printf("日:%d\n", p->tm_mday);	
	return 0;
}

2.进程线程及通信

1.进程与线程笔记

1.与进程相关的Linux命令(笔记)
1.top
	进程动态显示
2.pstree
	显示进程树
3.ps -aux
	R 运行状态
	S 睡眠状态
	D 磁盘休眠状态
	T 停止状态
	X 死亡状态
	
	s 进程领导者
	l 线程领导者
	+ 前端运行
	< 高优先级
	N 低优先级
4.nice
	nice <优先值> <进程名> - 通过给定的优先值启动一个程序
	nice -n  5  ./1    
5.ps -al //查看优先级
	PRI: 进程的优先级(默认80) 数字越低,优先级越高xs
	NI:  进程的谦让度(默认0) -20 ~ 19
	新的PRI = 旧PRI + NI
6.renice//修改进程的优先级
	1.程序还没有执行:
		nice -n  XX  ./a.out   XX是个具体的数字
		nice -n  5  ./1    
			
	5.程序在执行:
		renice -n  XX  -p  PID   XX是个具体的NI的数字
		renice -n  5  -p  4410
		
		NI的值的变化是以默认值为基准
		PRI都是以默认值为基准进行修改
7.kill
	1.使用 kill -信号数字 pid
		f
	2.常用信号 
		2  SIGINT	 停止进程	Ctrl+c		
		3  SIGQUIT 	 停止进程	ctrl+\
		9  SIGKILL	 停止进程(不能被阻塞,不能被捕获,不能忽略)
		10 SIGUSR1   用户自定义信号
		12 SIGUSR2	 用户自定义信号
		14 SIGALRM 	 停止进程
		18 SIGCONT   继续进程		
		19 SIGSTOP	 暂停进程(不能被阻塞,不能被捕获,不能忽略)
		20 SIGTSTP	 暂停进程 ctrl + z	
8.fg与bg
	1.让程序在后台运行 
		程序+ &
		如 ./a.out &
	2.运行时后台变前台
		在运行的终端jobs 显示进程编号
		fg + 编号
	3.运行时前台变后台 //要在当前终端
		crtl + z 暂停进程
		jobs 查看进程编号
		bg + 编号
2.与进程相关的函数(笔记)
1.fork()
#include <unistd.h>
pid_t fork(void)
	返回值fork()系统调用有两个返回值
	大于0,父进程
	等于0,子进程
	小于0,说明fork()出错。

2.获取pid
	1.pid_t getpid(void)   */自已的pid
	2.pid_t getppid(void)  */组进程pid
	3.pid_t getpgid(void)  */父进程pid

execl	execlp	execv	execvp
3.execl()
int execl(const char *path, const char *arg, ...)
	path:可执行文件的路径名字
	arg:可执行程序所带的参数,第一个参数为可执行文件名字,没有带路径且arg必须以NULL结束
	
4.execlp()
int execlp(const char *file, const char *arg, ...)
	file:如果参数file中包含/,则就将其视为路径名,否则就按PATH环境变量,在它所指定的各目录中搜寻可执行文件
	arg
 
5.execv()
int execv(const char *path, char *const argv[])
	path	   
	argv[]   
	
6.execvp()
int execvp(const char *file, char *const argv[])
	file
	argv[]
7.execle()
int execle(const char *path, const char *arg,
              ..., char * const envp[])
	path	   
	arg	   
	   		
8.execvpe()
int execvpe(const char *file, char *const argv[],
				char *const envp[])  
	path	   
	argv[]   
	
	*/总结
	l:(list) 参数一个个列出来
	v:(vector) 参数用数组存储,然后将该数组的地址作为这些函数的参数。
	p:使用文件名,并从PATH环境进行寻找可执行文件
	e:多了envp[]数组,使用新的环境变量代替调用进程的环境变量
	
	echo $PATH /查看环境变量
	export PATH = $ PATH: /临时路径
	vi ~/.bashrc 最后一行增加export PATH = $ PATH: /永久路径
	souce ~/.bashrc

9.wait()      */等待回收子进程
pid_t wait(int *status)
	status
	返回值:结束子进程的进程号,无子进程则返回-110.waitpid()  */等待回收子进程
pid_t waitpid(pid_t pid, int *status, int option)
		pid:
			>0 :回收指定ID的子进程
			-1 :回收任意子进程(相当于wait)
			0  :回收和当前调用waitpid一个组的所有子进程
			<-1:回收指定进程组内的任意子进程
			
		status:
			WIFEXITED(status):    若为正常终止子进程返回真(此参数是查看进程是否是正常退出)
			WEXITSTATUS(status):  若WEXITSTATUS非零,提取子进程退出码(查看进程的退出码)
			NULL
		options:
			0:不阻塞
			WNOHANG: 阻塞,如果没有任何已经结束的子进程则马上返回,不予以等待。 
			WUNTRACED:如果子进程进入暂停执行情况则马上返回,但结束状态不予以理会。
			
		返回值:	
			正常返回收集到的子进程的进程ID;
			设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,返回0;
			出错,则返回-1
3.守护进程创建步骤与应用(笔记)
1.守护进程创建步骤
	1.创建子进程,结束父进程  后台运行
	2.设置子进程为一个会话    摆脱父进程
	3.创建子进程,结束父进程  禁止打开终端的能力
	4.关闭所有的文件描述符    节省资源
	5.改变目录                不在根目录下
	6.改变掩码                拥有足够的权限
	7.重定向标准输入输出出错到null    守护进程不需要输入输出   

2.创建系统日志(守护进程)
	1.设置会话
	#include <unistd.h>
	pid_t setsid(void);
		成功返回会话id
		失败返回-1
		
	2.获取文件描述符
	#include <unistd.h>
	long sysconf(int name)

	3.更改目录
	#include <unistd.h>
	int chdir(const char *path)
	int fchdir(int fd)
	成功返回0,失败返回-1

	4.打开系统日志
	#include <syslog.h>
	void openlog(const char *ident, int option, int facility)
		ident:用户定义
		option:LOG_PID
		facility:LOG_DAEMON
		
	5.写入系统日志
	void syslog(int priority, const char *format, ...)
		priority:报文优先级
			LOG_ERR
			LOG_INFO
		format:格式
		
	6.关闭系统日志
	void closelog(void)

	#include <stdarg.h>
	void vsyslog(int priority, const char *format, va_list ap)
4.文件锁(笔记)
1.flock()   */ flock 函数只能对整个文件上锁 flock 只能产生劝告性锁 
#include <sys/file.h>
int flock(int fd, int operation);
	fd:文件描述符
	operation
		LOCK_SH:shared共享锁
		LOCK_EX:exclusive排它锁
		LOCK_UN:解锁
		LOCK_NB:不阻塞
2.lockf()     */设置文件锁 劝告性锁
#include <unistd.h>
int lockf(int fd, int cmd, off_t len)
	fd:文件描述符。
	cmd:
		F_LOCK:  给文件互斥加锁,若文件以被加锁,则会一直阻塞到锁被释放。
		F_TLOCK: 同F_LOCK,但若文件已被加锁,不会阻塞,而回返回错误。
		F_ULOCK: 解锁。
		F_TEST:  测试文件是否被上锁,若文件没被上锁则返回0,否则返回-1。
	len:为从文件当前位置的起始要锁住的长度。
	*/通过函数参数的功能,可以看出lockf只支持排他锁,不支持共享
3.fcntl()   */设置文件锁   强制锁
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
	fd:文件描述符
	cmd: 
		F_GETLK:检测锁状态
		F_SETLK:设置锁
		F_SETLKW:F_GETLK的阻塞版
		
			struct flock
			{
				short_l_type;    /*锁的类型*/
				short_l_whence;  /*偏移量的起始位置:SEEK_SET,SEEK_CUR,SEEK_END*/
				off_t_l_start;     /*加锁的起始偏移*/
				off_t_l_len;    /*上锁字节*/
				pid_t_l_pid;   /*锁的属主进程ID */
			}; 
	返回值:成功返回0,失败返回-1


4.access()    */文件判断
#include<unistd.h>
int access(const char* pathname, int mode)
	pathname:是文件的路径名+文件名
	mode:指定access的作用,取值如下
		F_OK 值为0,判断文件是否存在
		X_OK 值为1,判断对文件是可执行权限
		W_OK 值为2,判断对文件是否有写权限
		R_OK 值为4,判断对文件是否有读权限
	返回值:成功0,失败-1
5.无名管道与命名管道(笔记)
1.pipe        */创建无名管道 */用于父子兄弟进程间通信
#include <unistd.h>
int pipe(int pipefd[2])
	pipefd[0]:无名管道读端
	pipefd[1]:无名管道写端
	返回值,成功返回0,失败返回-1

2.mkfifo()   */创建命名管道
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode)
	pathname:文件名
	mode_t mode:权限
	返回值,成功返回0,失败返回-1
	
*/注意:
	open() 以只读方式打开 FIFO 时,要阻塞到某个进程为写而打开此 FIFO
	open() 以只写方式打开 FIFO 时,要阻塞到某个进程为读而打开此 FIFO
	只读等着只写,只写等着只读,只有两个都执行到,才会往下执行
	以读写方式打开 FIFO 文件,这样 open() 函数就不会阻塞
	假如 FIFO 里没有数据调用read()函数从FIFO里读数据read()也会阻塞
6.进程间通信相关函数(笔记)

1.信号函数

1.kill()     */发送信号
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig)
	pid:
		>0  给进程为pid的进程发送信号
		=0  给在同一个进程组下的所有进程发送信号
		-1  给任意进程发送信号,但是不包括init
		<-1 给进程组Id为pid绝对值的进程发信号
	sig:
	返回值,成功返回0,失败返回-1


2.raise()    */对自已发送信号
#include <signal.h>
int raise(int sig);
	相当于kill(getpid(), sig)

3.alarm()    */定时结束进程
#include <unistd.h>
unsigned int alarm(unsigned int seconds)
	seconds:秒数
	返回值:第一次设置返回0,第二次返回值第一次剩下的秒数,并重置秒数
	*/倒计时,时间到了就终止信号SIGALRM

4.signal()    */注册信号
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler)
	signum:信号
	handler:
		SIG_IGN:忽略
		SIG_DFL:默认
		捕捉:去调函数
		
5.pause()    */挂起
#include <unistd.h>
int pause(void);
	当捕捉到信号,并执行函数
	自动结束

2.共享内存

共享内存:在内核串开辟一块空间,用于保存和操作数据
	1.创建或者使用共享内存
	2.将共享内存地址映射到用户进程空间
	3.对这个映射地址操作
	4.解除映射关系
	5.删除共享内存
	
	ipcs-m查看共享内存
	ipcrm -m
			
1.shmget()	 */创建共享内存	
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg)
	key:标识
		获取key:IPC_PcRIVATE()系统自动分配
		手动创建key:ftok()
	size:共享内存的大小
	shmflg:IPC_CREAT | 0666
	返回值:返回共享内存的ID,出错返回-1    

2.ftok()    */获取key
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id)
	pathname:一个带路径的文件名,文件必须存在且有权访问
	proj_id:1-255随机

3.shmat()   */映射
void *shmat(int shm_id, const void *shm_addr, int shmflg)
	shm_id:是由shmget函数返回的共享内存标识。
	shm_addr:指定共享内存连接到当前进程中的地址位置,通常为空让系统来选择共享内存的地址。
	shm_flg:是一组标志位,通常为0,表示可读可写
	返回值:成功返回指向共享存储段的地址,出错返回-1
	
4.shmdt()   */解除映射
int shmdt(const void *shmaddr)
	addr:以前调用shmat时的返回值
	返回值:成功返回0,出错返回-1
	这并不是从系统中删除其标识符以及其数据结构,删除本进程对这块内存的使用
5.shmctl()   */删除共享内存	
int shmctl(int shm_id, int cmd, struct shmid_ds *buf)
	shm_id:是shmget函数返回的共享内存标识符。
	cmd:是要采取的操作   
		IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值。    
		IPC_SET:设置共享内存的信息
		IPC_RMID:删除共享内存段, buf:NULL
	buf:是一个结构指针,它指向共享内存模式和访问权限的结构。 shmid_ds结构至少包括以下成员
		struct shmid_ds 
		{ 
			uid_t shm_perm.uid; 
			uid_t shm_perm.gid; 
			mode_t shm_perm.mode; 
		};
	返回值:成功返回0,出错返回-1

3.信号量

信号量:信号量是一种特殊的变量,来解决进程或线程间共享资源引发的同步问题。

	ipcs -s     */查看信号
	ipcrm -s    */删除信号
	
1.semget()   */新建信号量
int semget(key_t key,int num_sems,int sem_flags)
	key:信号量键值,和共享内存一样。
	num_sems:信号量的个数
	sem_flags:
		IPC_CREATE:若信号量已存在,返回该信号量标识符
		IPC_EXCL:若信号量已存在,返回错误。
	返回值:成功返回信号量标识符,失败返回-1


2.semop()  */修改信号量的值
int semop(int sem_id,struct sembuf *sem_opa,size_t num_sem_ops)
	sem_id:信号量标识符
	sem_opa:数组
		struct sembuf
		{  
			short sem_num;灯的下标,从0开始,除非使用一组信号量,否则它为0  
			short sem_op;-1,即P(等待)操作,+1,即V(发送信号)操作。  
			short sem_flg:
		}		0:阻塞
				IPC_NOWAIT:不阻塞
				SEM_UNDO,则当进程退出的时候会还原该进程的信号量操作
	num_sem_ops:数组的大小

3.semctl()    */用于信号量的初始化和删除
int semctl(int sem_id,int sem_num,int command,[union semun sem_union])
	sem_id:信号量标识符
	sem_num:灯的下标
	command:
		GETVAL:获取信号val值
		SETVAL:设置信号val值
		IPC_RMID:删除信号灯  NULL
	sem_union:可选参数
		union semun
		{  
			int val; 
			struct semid_ds *buf;  
			unsigned short *arry;  
		}; 
		*/一般用到的是val,表示要传给信号量的初始值
8.消息队列
	ipcs -q           */查看信号
	ipcrm -q msgmid   */删除信号

1.msgget()      */创建消息队列
#include<sys/msg.h>
int msgget(key_t key,int flag)   
	key:为ftok生成的键值
	flag:操作和权限
		IPC_CREAT:如果不存在key值的消息队列则创建消息队列如果存在,则直接返回消息队列ID。
		IPC_CREAT | IPC_EXCL:如果不存在key值的消息队列则创建消息队列,如果存在,则产生错误。
	返回值:成功返回消息队列ID;出错返回-1

2.msgsnd()     */往消息队列发送消息
int msgsnd(int msgid,const void *ptr,size_t nbytes,int flag);
	msgid:为msgget返回的消息队列ID值
	ptr:消息结构体mymesg指针
	nbytes:为消息结构体mymesg里的字符数组mtext大小,sizeof(mtext)
	flag:
		0:当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列或者消息队列被删除。
		IPC_NOWAIT:当消息队列满了,msgsnd函数将不会等待,会立即出错返回EAGAIN
	返回值:成功返回0;错误返回-1

3.msgrcv()     */从消息队列读取消息
ssize_t msgrcv(int msgid,void *ptr,size_t nbytes,long type,int flag);
	msgid:为msgget返回的消息队列ID值
	ptr:为消息结构体mymesg指针
		struct msgbuf
		{
			long mtype; 
			char mtext[100];
		};
	nbytes:为消息结构体mymesg里的字符数组mtext大小,sizeof(mtext)
	type:在结构体mymesg里我们定义了一个long int mtype,用于分别消息的类型
		type ==0:返回队列中的第一个消息
		type > 0:返回队列中消息类型为type的第一个消息
		type < 0:返回队列中消息类型值小于等于type绝对值的消息,如果这种消息有若干个,则取类型值最小的消息
	flag:
		0:阻塞式接收消息,没有该类型的消息msgrcv函数一直阻塞等
		IPC_NOWAIT:如果没有返回条件的消息调用立即返回,此时错误码为ENOMSG
		IPC_EXCEPT:与msgtype配合使用返回队列中第一个类型不为msgtype的消息
	返回值:成功返回消息数据部分的长度,错误返回-1
	
4.msgctl()   */对消息队列进行控制
int msgctl(int msgid, int cmd, struct msqid_ds *buf)
	msgid:msgget函数返回的消息队列ID
	cmd:
		IPC_RMID:删除消息队列
		IPC_STAT:取此队列的msqid_ds结构,并将它存放在buf指向的结构中;
		IPC_SET:改变消息队列的状态,把buf所指的msqid_ds结构中的uid、gid、mode复制到消息队列的msqid_ds结构内。(内核为每个消息队列维护着一个结构,结构名为msqid_ds,这里就不讲啦,里面存放着消息队列的大小,pid,存放时间等一些参数)
	buf:结构体msqid_ds
	返回值:成功返回0;错误返回-1
7.进程与线程相关概念(笔记)
1.并行与并发
	并发:同一时刻只有一条指令执行,多个进程指令快速轮换执行
	并行:同一时该多条指令在多个处理机上执行
2.同步与互斥
	同步:进程相互依赖
	互斥:进程相互排斥使用资源
	
3.同步与异步
	同步:顺序执行,需要等待协调运行
	异步:彼此独立,不需要其它线程的等待
4.进程与线程
	进程:最小分配资源单位,调度的最小单位,独立的地址空间,拥有pcb
	线程:最小的执行单位,调度的基本单位
	
6.线程共享的资源与独立的资源
	1.共享的资源
		同一块地址空间
		文件描述符表
		每种信息的处理方式
		当前工作目录
		用户id组id
	2.独立的资源
		线程产生的临时变量
		线程id
		......
主线程和子线程共享:.text段,.bss段 .data段, 堆,动态库加载区
主线程和子线程不共享:
9.线程的创建与回收(笔记)
1. pthread_create()     */线程创建
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg)

	thread:  指向线程标识符的指针
  attr:    设置线程属性
  void *:  线程运行函数的地址
  arg:     是运行函数的参数
	返回值:  成功返回0,失败返回出错编号

2. pthread_self()    */获取线程id
#include <pthread.h>
	返回值:线程id

3. pthread_join()	*/线程等待
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval)
	thread: 线程标识符,即线程ID,标识唯一线程。
	retval:用户定义的指针,用来存储被等待线程的返回值。
	返回值 :成功返回0,失败返回错误号。
		*/以阻塞的方式等待thread指定的线程结束。
		*/当函数返回时,被等待线程的资源被收回。
		*/如果线程已经结束,那么该函数会立即返回。
		*/在多线程环境中,父线程终止,全部子线程被迫终止

4. pthread_exit()   */结束线程
#include <pthread.h>
void pthread_exit(void *retval)


5.1 pthread_attr_init()    */初始化属性	
#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr); 
	
	返回值:成功返回0

5.2 pthread_atrr_setdetachstate()    */设置线程属性
#include <pthread.h>
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
	attr:
	detachstate:分离属性、调度属性、堆栈大小属性和满占警戒区大小属性	

5.3. pthread_attr_destory()   */删除线程属性
#include <pthread.h>
int pthread_attr_destory(pthread_attr_t *attr); 	

6. pthread_detach()   */设置分离属性
int pthread_detach(pthread_t tid);	

6.2 pthread_attr_setscope()  */设置绑定属性的接口
int pthread_attr_setscope(pthread_attr_t *attr, int scope);
	attr:线程属性对象的指针,
	scope:绑定类型
			PTHREAD_SCOPE_SYSTEM(绑定的)
			PTHREAD_SCOPE_PROCESS(非绑定的)

10.线程同步与互斥(笔记)
1. sem_init()   */信号初始化
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
	sem:信号灯标识
	pshared:进程下所有线程都可使用
	value:信号灯初始值
	返回值:成功返回0,失败返回-1
2. sem_wait()    */p操作
#include <semaphore.h>
int sem_wait(sem_t *sem);
	sem:信号灯标识
	返回值:成功返回0,失败返回-1

3. sem_post()     */v操作
#include <semaphore.h>
int sem_post(sem_t *sem);
	sem:信号灯标识
	返回值:成功返回0,失败返回-1
	
4. sem_destroy()    */删除信号
#include <semaphore.h>
int sem_destroy(sem_t *sem);
	sem:信号灯标识
	返回值:成功返回0,失败返回-1
线程互斥:互斥就是线程之间互相排斥,获得资源的线程排斥其它没有获得资源的线程
1. pthread_mutex_init()      */初始化
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr) 
	mutex:标识
	attr:NULL
	返回值:成功返回0,失败返回-1
	
2. pthread_mutex_lock()      */上锁
int pthread_mutex_lock(pthread_mutex_t *mutex)
	mutex:标识
	返回值:成功返回0,失败返回-1

3. pthread_mutex_unlock()    */解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex)
	mutex:标识
	返回值:成功返回0,失败返回-1
4. pthread_mutex_destory()   */删除锁
int pthread_mutex_destory(pthread_mutex_t *mutex ) 
	mutex:标识
	返回值:成功返回0,失败返回-1
	
5. pthread_mutex_trylock()
int pthread_mutex_trylock(pthread_mutex_t *mutex)
	mutex:标识
	返回值:成功返回0,失败返回-1

2.进程线程及通信函数的使用

1.进程函数的使用(代码)
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
	pid_t pt;
	pt = fork();
	if(pt < 0)
	{
		perror("fork");
		exit(-1);
	}
	if(pt == 0)
	{
		printf("子进程runing...\n");
		printf("子进程pid:%d,其父进程pid:%d\n", getpid(), getppid());
		sleep(5);
	}
	if(pt > 0)
	{
		printf("父进程runing...\n");
		printf("等待子进程结束...\n");
		
		pid_t pid;
		wait(&pid);
		printf("回收的子进程pid:%d", pid);
	}
	return 0;
}

waitpid

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
	pid_t pt1 = fork();
	pid_t pt2;
	if(pt1 < 0)
	{
		perror("fork");
		exit(-1);
	}
	
	//如果是子进程1就退出
	if(pt1 == 0)
	{
		printf("son1 %d,其父进程为%d\n",getpid(), getppid());
		exit(1);
	}
	pt2 = fork();
	if(pt2 < 0)
	{
		perror("fork");
		exit(-1);
	}
	//子进程2退出
	if(pt2 == 0)
	{
		printf("son2 %d,其父进程为%d\n",getpid(), getppid());
		exit(-1);
	}
	sleep(1);
	printf("准备回收\n");
	pid_t pid = waitpid(pt2, NULL, 0);
	printf("被回收进程pid:%d", pid);
	return 0;
}
#include <stdio.h>
#include <unistd.h> 
int main(int argc, char *argv[])
{
	//1.执行本进程
	if(argc != 2)
	{
		printf("usage : %s <filename>\n", argv[0]);
		return -1;
	}
	printf("play...\n");
	sleep(1);
	
	//2.切换进程
	sleep(5);
	execl( argv[1], argv[1], NULL);//可执行文件带路径;可执行文件名字;可执行文件的参数列表,最后一个参数为NULL
	//execlp( argv[1], argv[1], NULL);//可执行文件带路径(PATH,不包含./);可执行文件名字;可执行文件的参数
	
	//3.被切换后不执行
	printf("ok\n");
	return 0;
}
#include <stdio.h>
#include <unistd.h> 
int main(int argc, char *argv[])
{
	//1.执行本进程
	if(argc != 2)
	{
		printf("usage : %s <filename>\n", argv[0]);
		return -1;
	}
	printf("play...\n");
	sleep(1);
	
	//2.切换进程
	sleep(5);
	//第三个参数为可执行文件的参数列表封装的数组
	execlv( argv[1], argv[1], NULL);//可执行文件带路径;可执行文件名字;可执行文件的参数数组
	//execlvp( argv[1], argv[1], NULL);//可执行文件带路径(PATH,不包含./);可执行文件名字;可执行文件的参数数组
	
	//3.被切换后不执行
	printf("ok\n");
	return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>

void init_daemon();
int main(int argc, char *argv[])
{
	
	if(argc != 2)
	{
		printf("usage :%s <filename>\n",argv[0]);
		return -1;
	}
	init_daemon();
	FILE *fp = fopen(argv[1], "a");
	if(fp == NULL)
	{
		perror("open");
		return -1;
	}
	
	while(1)
	{
		time_t tv;
		time(&tv);
		char *s = ctime(&tv);
		fputs(s, fp);
		fflush(fp);
		sleep(1);
	}
	fclose(fp);
	return 0;
}

void init_demo()
{
	
	//1.创建子进程,结束父进程  后台运行
	if(fork()!= 0)
	{
		exit(0);
	}
	//2.设置子进程为一个会话    摆脱父进程
	if(setsid() < 0)
	{
		perror("setsid error");
		exit(-1);
	}
	//3.创建子进程,结束父进程  禁止打开终端的能力
	if(fork() != 0)
	{
		exit(0);
	}
	//4.关闭所有的文件描述符    节省资源
	int i;
	for(i = 0; i < sysconf(_SC_OPEN_MAX); i++)
	{
		close(i);
	}

	//5.改变目录                不在根目录下
	chdir("/");
	
	//6.改变掩码                拥有足够的权限
	umask(0);
	
	//7.重定向标准输入输出出错到null    守护进程不需要输入输出                       
	open("/dev/null",O_RDWR);//输入
	dup(0);//输出
	dup(0);//出错
	
}
2.无名管道、有名管道、信号函数(代码)

无名管道

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char *argv[])
{
	int pipefd[2];
	int p = pipe(pipefd);
	if(p < 0)
	{
		perror("pipe error");
		return -1;
	}
	pid_t pt = fork();
	if(pt < 0)
	{
		perror("fork");
		return -1;
	}
	//子进程读
	else if(pt == 0)
	{
		close(pipefd[1]);
		char str[128] = {};
		read(pipefd[0], str, sizeof(str));
		printf("子进程%d读到:%s\n", getpid(), str);
		
	}
	//父进程写
	else
	{
		close(pipefd[0]);
		char str[128] = {};
		printf("父进程写入数据\n");
		scanf("%s", str);
		write(pipefd[1], str, strlen(str));
	}
}

有名管道

//有名管道只写端
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
	//1.判断管道是否存在
	if(access("./fifo", F_OK) == -1)
	{
	//2.不存在则创建管道
		if(mkfifo("./fifo", 0666) < 0)
		{
			perror("mkfifo");
			exit(-1);
		}
	}
	
	//3.打开管道
	int fd = open("./fifo", O_WRONLY);
	if(fd < 0)
	{
		perror("open");
		exit(-1);
	}
	
	//4.写数据
	char buf[100] = "hello";
	write(fd, buf, sizeof(buf));
	printf("数据已被读取...");
	sleep(5);
	
	//5.关闭管道
	close(fd);
	return 0;
}
//有名管道只读端
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
//管道只读端
int main(int argc, char *argv[])
{
	//1.判断管道是否存在
	if(access("fifo", F_OK) == -1)
	{
		//2.不存在则创建管道
		if(mkfifo("fifo", 0666) < 0)
		{
			perror("mkfifo");
			exit(-1);
		}
	}
	
	//3.打开管道
	int fd = open("fifo", O_RDONLY);
	if(fd < 0)
	{
		perror("fifo");
		exit(-1);
	}
	
	//4.读数据
	char buf[100];
	printf("准备读取数据...\n");
	sleep(3);
	read(fd, buf, sizeof(buf));
	printf("%s\n", buf);
	
	
	//5.关闭管道
	close(fd);
	
	return 0;
}

信号函数

//raise给自身进程发信号
#include <stdio.h>
#include <signal.h>

int main(int argc, char *argv[])
{
	printf("请输入要对此进程执行的信号\n");
	int sig;
	scanf("%d", &sig);
	raise(sig);	
	return 0;
}
//kill给任意进程发信号
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>

int main(int argc, char *argv[])
{
	int pid;
	int sig;
	printf("pid:%d\n", getpid());
	while(1)
	{
		printf("请输入要执行的进程\n");
		scanf("%d", &pid);
		printf("请输入要执行的信号\n");
		scanf("%d", &sig);
		kill(pid, sig);
	}
	return 0;
}
//alarm定时器
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
	
	printf("程序5秒后结束\n");
	alarm(5);
	int i = 0;
	while(1)
	{
		i++;
		sleep(1);
		printf("time:%d\n", i);
	}
}
//signal注册信号
#include <stdio.h>
#include <signal.h>

void show(int num)
{
	printf("执行sinnal的绑定的函数\n");
}

int main(int argc, char *argv[])
{	
	signal(2, show);
	signal(3, SIG_IGN);//忽略
	//signal(3, SIG_DFL);//默认
	pause();	
	while(1);
	return 0;
}
3.共享内存、信号量、消息队列(代码)

共享内存

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main(int argc, char *argv[])
{
	//1 获取key
	key_t key = ftok("./ftok", 0);
	printf("key:%d\n", key);

	//2 创建共享内存
	int shmid = shmget(key, 1024, IPC_CREAT | 0666);
	printf("shmid:%d\n", shmid);
	
	//3 映射
	char *ptr = (char *)shmat(shmid, NULL, 0);
	strcpy(ptr, "数据写入至共享内存");
	printf("ptr:%s\n", ptr);
	
	//4 解除映射
	shmdt(ptr);
	
	//5 删除共享内存
	if(shmctl(shmid, IPC_RMID, NULL) == 0)
	{
		printf("删除共享内存%d成功\n", shmid);
	}	
	return 0;
}

信号量

//被阻塞程序
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int main(int argc, char *argv[])
{
	
	key_t key = ftok("./ftok", 0);
	printf("key:%d\n", key);
	
	int semid = semget(key, 1, IPC_CREAT | 0666);
	printf("semid:%d\n", semid);
	
	printf("阻塞中...\n");
	struct sembuf buf = {0, -1, 0};//第一个信号;减1操作;阻塞
	semop(semid, &buf, 1);//1 为数组大小
	
	printf("解除阻塞\n");
	
	if(semctl(semid, 0, IPC_RMID, NULL) == 0)`	
	{
		printf("删除信号集%d成功\n", semid);
	}
	
	return 0;
}
//解除前一程序阻塞
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int main(int argc, char *argv[])
{
	key_t key = ftok("./ftok", 0);
	printf("key:%d\n", key);
	
	int semid = semget(key, 1, IPC_CREAT | 0666);
	printf("semid:%d\n", semid);
	
	int i;
	printf("请输入任意数解除另一程序阻塞\n");
	scanf("%d", &i);
	
	struct sembuf buf = {0, 1, 0};
	semop(semid, &buf, 1);
	
	printf("已解除阻塞\n");
	
	return 0;
}

消息队列

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct msgbuf
{
	long mtype; 
	char mtext[128];
};

int main(int argc, char *argv[])
{
	key_t key = ftok("./ftok", 0);
	printf("key:%d\n", key);
	
	int msgid = msgget(key, IPC_CREAT | 0666);
	printf("msgid:%d\n", msgid);
	struct msgbuf buf1 = {1, "王宝强"};
	msgsnd(msgid, &buf1, 128, 0);
	
	struct msgbuf buf2 = {1, "王思聪"};
	msgsnd(msgid, &buf2 , 128, 0);
	
	struct msgbuf buf4 = {2, "马化腾"};
	msgsnd(msgid, &buf4, 128, 0);
	
	struct msgbuf buf5 = {3, "马云"};
	msgsnd(msgid, &buf5, 128, 0);
	
	printf("输入任意数删除消息队列\n");
	int i;
	scanf("%d", &i);
	
	if(msgctl(msgid, IPC_RMID, 0) == 0)
	{
		printf("消息队列%d删除成功\n", msgid);
	}
	return 0;
}
4.线程函数的使用(代码)
//pthread_create的使用
#include <stdio.h>
#include <pthread.h>

void *show(void *arg)
{
	//3.线程id
	printf("phread tid:%lu\n", pthread_self());
	sleep(5);
	
	//4.线程结束
	pthread_exit("pthread return");
}

int main(int argc, char *argv[])
{
	
	//1.创建线程
	pthread_t tid;
	pthread_create(&tid, NULL, show, NULL);
	char *ret;
	
	//2.回收线程获取返回值
	pthread_join(tid, (void *)&ret);
	printf("%s\n", (char *)ret);
	return 0;
}
//phread_detach的使用
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
int flag = 0;

void *show(void *arg)
{
	sleep(5);
	flag = 1;
	pthread_exit(NULL);
	
}

int main(int argc, char *argv[])
{
	//1.创建线程
	pthread_t tid;
	pthread_create(&tid, NULL, show, NULL);
	
	//2.设置分离属性
	pthread_detach(tid);
	
	printf("phread wait...\n");
	while(1)
	{
		if(flag == 1)
		{
			break;
		}
	}
	printf("pthread teturn\n");
	
	return 0;
}
//pthread_mutex线程锁的使用
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

//0.锁变量
pthread_mutex_t pmt;
int a = 10;
int b = 10;
void *metuxadd(void *arg)
{
	while(1)
	{
		sleep(2);
		//5.获取锁
		pthread_mutex_lock(&pmt);
		printf("进程1获取锁\n");
		a++;
		b++;
		printf("%d\n", a);
		printf("%d\n", b);
		//6.释放锁
		pthread_mutex_unlock(&pmt);
	}
	pthread_exit(NULL);
}

void *metuxsub(void *arg)
{
	while(1)
	{
		sleep(1);
		pthread_mutex_lock(&pmt);
		printf("进程2获取锁\n");
		a--;
		b--;
		printf("%d\n", a);
		printf("%d\n", b);
		pthread_mutex_unlock(&pmt);
	}
	pthread_exit(NULL);
}

int main(int argc, char *argv[])
{
	//1.创建线程锁
	pthread_mutex_init(&pmt, NULL);
	
	//2.创建线程
	pthread_t tid1, tid2;
	pthread_create(&tid1, NULL, metuxadd, NULL);
	pthread_create(&tid2, NULL, metuxsub, NULL);
	
	//3.等待线程
	pthread_join(tid1, NULL);
	pthread_join(tid2, NULL);
	
	//4.销毁线程锁
	pthread_mutex_destroy(&pmt);
	return 0;
}
5.文件日志与文件锁-未完成(代码)

3.网络

1.网络编程笔记

1.tcp/ip相关函数(笔记)
	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <arpa/inet.h>
	1. inet_aton()     */十进制ip主机字节序转网络字节序
	int inet_aton(const char *cp, struct in_addr *inp)
		cp:要转的ip地址
		inp:存放的结构体
	2. inet_addr()     */十进制ip主机字节序转网络字节序
	in_addr_t inet_addr(const char *cp)
		cp:要转的ip地址
	
	3. inet_ntoa()
	char *inet_ntoa(struct in_addr in)
	
	1.socket() 
	#include <sys/socket.h> 
	int socket(int af, int type, int protocol);
		af:IP 地址类型
			AF_INET
			AF_INET6
		type:数据传输方式/套接字类型
			SOCK_STREAM(流格式套接字/面向连接的套接字)
			SOCK_DGRAM(数据报套接字/无连接的套接字
		protocol:表示传输协议
			IPPROTO_TCP
			IPPTOTO_UDP
		返回值:套接描述符
			
	2.bind()
	int bind(int sock, struct sockaddr *addr, socklen_t addrlen);  //Linux
		sock :socket 文件描述符
		addr:sockaddr 结构体变量的指针
		addrlen:addr 变量的大小,由 sizeof() 计算。
		返回值:成功返回0,失败回-1

			struct sockaddr_in
			{
				sa_family_t     sin_family;   //地址族(Address Family),也就是地址类型
				uint16_t        sin_port;     //16位的端口号
				struct in_addr  sin_addr;     //32位IP地址
				char            sin_zero[8];  //不使用,一般用0填充
			};
			struct in_addr
			{
				in_addr_t  s_addr;  //32位的IP地址
			};
		struct sockaddr_in serv_addr;
		
	3.connect() 函数      */连接   客户端使用
	int connect(int sock, struct sockaddr *serv_addr, socklen_t addrlen);  //Linux
		sock :socket文件描述符
		addr:存放服务器端ip, sockaddr结构体变量的指针
		addrlen:addr 变量的大小,由 sizeof() 计算
		返回值:成功返回大于0,失败返回-1
		
	4.listen() */套接字进入被动监听状态   服务器端使用
	int listen(int sock, int backlog); 
		sock:套接字
		backlog:请求队列的最大长度(同时连接客户端量大数量)

	5.accept()    */当套接字处于监听状态时,接收客户端请求
	int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);  //Linux
		sock:服务器端套接字,
		addr:客户端ip等,sockaddr_in 结构体变量
		addrlen:结构体大小的地址
		返回值:成功返回新的文件描述符用于通信,失败返回-1

	6.send() /recv()
	#include <sys/types.h>
	#include <sys/socket.h>
	ssize_t send(int sockfd, const void *buf, size_t len, int flags);
	ssize_t recv(int sockfd, const void *buf, size_t len, int flags);
		sockfd:文件描述符
		buf:缓冲区地址
		len:发送的字节数/想接收的字节数
		flags:0
		返回值:成功返回字节数,失败返回-1
2.端口复用函数(笔记)
	7.select()
	#include <sys/time.h>
	#include <sys/types.h>
	#include <unistd.h>
	int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
		nfds:最大文件描述符加1
		readfds:读就绪
		writefds:写就绪
		exceptfds:其它
		timeout:超时间
			>0
			==0
			<0
		返回值:成功返回个数,失败返回1

	void FD_CLR(int fd, fd_set *set)      */清除文件描述符
	int  FD_ISSET(int fd, fd_set *set)    */判断在集合中有无文件描述符
	void FD_SET(int fd, fd_set *set);     */设置
	void FD_ZERO(fd_set *set);            */清空集合

	8.poll()
	#include <poll.h>
	int poll(struct pollfd *fds, nfds_t nfds, int timeout);
		fds:集合的首地址
		nfds:集合文件描述符个数
		timeout:
			>0:阻塞对应的时间
			==0 : 不阻塞
			-1 : 一直阻塞

			struct pollfd 
			{
				int   fd;      //文件描述符
				short events;  //请求事件: POLLRDNORM    POLLWRNORM   POLLERR
				short revents; // 返回事件   //实际发生的事
			};
				POLLIN         普通或优先级带数据可读
				POLLRDNORM     普通数据可读
				POLLRDBAND     优先级带数据可读
				POLLPRI        高优先级数据可读
				POLLOUT        普通数据可写
				POLLWRNORM     普通数据可写
				POLLWRBAND     优先级带数据可写
				POLLERR        发生错误
				POLLHUP        发生挂起
				POLLNVAL       描述字不是一个打开的文件
3.udp/ip相关函数(笔记)
	9.setsockopt()
	#include <sys/types.h>          /* See NOTES */
	#include <sys/socket.h>
	int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen);
	int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
		fd:文件描述符
		level:层次
			SOL_SOCKET:通用套接字选项.
			IPPROTO_IP:IP选项.
			IPPROTO_TCP:TCP选项. 
		level:层次
			SOL_SOCKET:通用套接字选项
			IPPROTO_IP:IP选项
			IPPROTO_TCP:TCP选项

		optname:选项
			SOL_SOCKET:
			SO_BROADCAST        允许发送广播数据         int
			SO_RCVTIMEO         接收超时                 struct timeval
			SO_REUSEADDR        允许重用本地地址和端口   int

			IPPROTO_IP:
			IP_ADD_MEMBERSHIP   将ip添加到组		     struct ip_mreq

			IPPROTO_TCP:
			TCP_NODELAY         不使用Nagle算法          int
		optval:选项待设置的值
		optlen:值所占空间大小
		1.设置端口号可以重用
			int on=1;
			setsockopt(fd, SOL_SOCKET,SO_REUSEADDR,&on, sizeof(on));
		2.设置可以发送广播数据
			int on=1;yf
			setsockopt(fd, SOL_SOCKET, SO_BROADCAST,&on, sizeof(on));
		3.设置阻塞的超时时间为5struct timeval 
			{
				long    tv_sec;         /* seconds */
				long    tv_usec;        /* microseconds */
			};
			struct timeval tv={5,0};
			setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,&tv, sizeof(tv));
		4.将本地ip地址加入到多播组中
			struct ip_mreq
			{
				struct in_addr imr_multiaddr;   /* IP multicast address of group */
				struct in_addr imr_interface;   /* local IP address of interface */
			};
			struct ip_mreq iq;
			iq.imr_multiaddr.s_addr=inet_addr("230.230.230.230");
			iq.imr_interface.s_addr=inet_addr("192.168.90.100");
			setsockopt(fd, IPPROTO_IP,IP_ADD_MEMBERSHIP,&iq, sizeof(iq));
4.sqlite3库函数(笔记)
1. sqlite3_open()     */打开数据库链接
int sqlite3_open(const char *filename, sqlite3 **ppDb);
	filename:数据库文件名,不存在会自动创建
	ppDb:数据库链接

2. sqlite3_close()    */关闭数据库链接
int sqlite3_close(sqlite3 *ppDb);
	filename:数据库文件名,不存在会自动创建
	ppDb:数据库链接
	
3. sqlite3_exec()
int sqlite3_exec(sqlite3 *db,char *sql,int (*callback)(void *arg,int col,char **str,char **name),void *arg,char **errmsg);
	db:句柄
	sql:要执行的sql语句
	callback:函数指针,只有查询命令时调用
	arg:传进去的参数
	errmsg:存放错误信息
	返回值:成功返回SQLITE_OK
	
4.callback()
int (*callback)(void *arg,int col,char **str,char **name)
	callback : 函数地址
	arg:传进来的参数
	col:总列数
	str:存放查询到的一组信息
	name:表头
5.json库函数(笔记)
	
1、数据的封装(单对象(intchar、string)和数组(arry))
	struct json_object * json_object_new_object (void)
	struct json_object * json_object_new_array (void)

2.son对象的转换(普通类型->json对象):
	struct json_object * json_object_new_int (int i)
	struct json_object * json_object_new_double (double d)
	struct json_object * json_object_new_string (const char *s)

3.json对象的处理

	//对象;键;值     将键值对加到对象串
	void json_object_object_add (struct json_object *obj, const char *key, struct json_object *val)
	void json_object_object_del (struct json_object *obj, const char *key)
	struct json_object * json_object_object_get (struct json_object *obj, const char *key)
	struct json_object * json_object_object_get (struct json_object *obj, const char *key)

	int json_object_array_length (struct json_object *obj)
	int json_object_array_add (struct json_object *obj, struct json_object *val)
	int json_object_array_put_idx (struct json_object *obj, int idx, struct json_object *val)
	struct json_object * json_object_array_get_idx (struct json_object *obj, int idx)

4. son_object To 字符流
	const char * json_object_to_json_string (struct json_object *obj)

1、数据的解析(解析获取到的json格式字符流)
1.字符流 To json_object
	struct json_object*	json_tokener_parse(const char *str)

2.对象获取
	//通过键获取
	struct json_object * json_object_object_get (struct json_object *obj, const char *key)
	//通过下标获取
	struct json_object * json_object_array_get_idx (struct json_object *obj, int idx)

3.对象的转换(数据还原)
	double json_object_get_double (struct json_object *obj)
	int json_object_get_int (struct json_object *obj)
	const char * json_object_get_string (struct json_object *obj)
	boolean json_object_get_boolean (struct json_object *obj)

2.网络编程函数使用

1.客户端服务器模型-tcp(代码)
//客户端 能实现循环发送与接收
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>  
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>

int fd;
void *read_msg(void *arg)
{
	char str[128];
	int len;
	while(1)
	{
		bzero(str, sizeof(str));
		len = recv(fd, str, sizeof(str), 0);
		if(len == 0 )
		{
			break;
		}
		printf("server:%s\n", str);
	}
	pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
	fd = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(40015);
	addr.sin_addr.s_addr = inet_addr("192.168.1.120");
	if(connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
	{
		perror("connect");
		exit(1);
	}
	//读
	pthread_t pt;
	pthread_create(&pt, NULL, read_msg, NULL);
	//写
	char str[128];
	while(1)
	{
		bzero(str, sizeof(str));
		scanf("%s", str);
		send(fd, str, strlen(str), 0);
	}
	return 0;
}
//服务器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>  
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>

int newfd;
void *recv_msg(void *arg)
{
	char str[128];
	int len;
	while(1)
	{
		bzero(str, sizeof(str));
		len = recv(newfd, str, sizeof(str), 0);
		if(len == 0)
		{
			pthread_exit(NULL);
		}
		printf("client:%s\n", str);
	}
}
int main(int argc, char *argv[])
{
	int fd = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(40015);
	addr.sin_addr.s_addr = inet_addr("192.168.1.120");
	if(bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
	{
		perror("bind");
		exit(1);
	}
	if(listen(fd, 10) < 0)
	{
		perror("listen");
		exit(1);
	}
	
	newfd = accept(fd, NULL, NULL);	
	printf("fd:%d, newfd:%d\n", fd, newfd);
	
	pthread_t pt;
	pthread_create(&pt, NULL, recv_msg, NULL);
	
	char str[128];
	while(1)
	{
		bzero(str, sizeof(str));
		scanf("%s", str);
		send(newfd, str, strlen(str), 0);		
	}
	
	//pthread_join(pt, NULL);
	return 0;
}
2.客户端服务器模型-tcp-select(代码)
//客户端 使用select函数实现读写端口复用
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/types.h>

int main(int argc, char *argv[])
{
	int fd = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(44444);
	addr.sin_addr.s_addr = inet_addr("192.168.1.120");
	if(connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
	{
		perror("connect");
		exit(1);
	}
	fd_set myset;
	char str[128];
	int ret;
	while(1)
	{
		bzero(str, sizeof(str));
		FD_ZERO(&myset);
		FD_SET(0, &myset);
		FD_SET(fd, &myset);
		select(fd+1, &myset, NULL, NULL, NULL);
		//输入
		if(FD_ISSET(0, &myset))
		{
			scanf("%s", str);
			send(fd, str, strlen(str), 0);
		}
		//输出
		if(FD_ISSET(fd, &myset))
		{
			int ret = recv(fd, str, sizeof(str), 0);
			if(ret == 0)
			{
				break;
			}
			printf("server:%s\n", str);
		}
	}	
	return 0;
}
//服务器 使用select函数实现读写端口复用
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/types.h>

int main(int argc, char *argv[])
{
	int fd = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(44444);
	addr.sin_addr.s_addr = inet_addr("192.168.1.120");
	if(bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
	{
		perror("bind");
		exit(1);
	}
	if(listen(fd, 10) < 0)
	{
		perror("listen");
		exit(1);
	}
	int newfd = accept(fd, NULL, NULL);
	printf("newfd:%d\n", newfd);
	char str[128];
	fd_set myset;
	while(1)
	{
		bzero(str, sizeof(str));
		FD_ZERO(&myset);
		FD_SET(0, &myset);
		FD_SET(newfd, &myset);
		select(newfd+1, &myset, NULL, NULL, NULL);
		//输入
		if(FD_ISSET(0, &myset))
		{
			scanf("%s", str);
			send(newfd, str, sizeof(str), 0);
		}
		//输出
		if(FD_ISSET(newfd, &myset))
		{
			int ret = recv(newfd, str, sizeof(str), 0);
			if(ret == 0)
			{
				break;
			}
			printf("client:%s\n", str);
		}	
	}
	return 0;
}
3.客户端服务器模型-tcp-poll(代码)
//客户端 poll函数实现读写端口复用
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/types.h>
#include <poll.h>

int main(int argc, char *argv[])
{
	int fd = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(44445);
	addr.sin_addr.s_addr = inet_addr("192.168.1.120");
	if(connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
	{
		printf("connect");
		exit(1);
	}
	struct pollfd fds[5];
	fds[0].fd = 0;
	fds[0].events = POLLRDNORM;
	fds[1].fd = fd;
	fds[1].events = POLLRDNORM;
	char str[128];
	int ret;
	while(1)
	{
		poll(fds, 2, -1);
		if(fds[0].revents & POLLRDNORM)
		{
			scanf("%s", str);
			send(fd, str, strlen(str), 0);
		}
		
		if(fds[1].revents & POLLRDNORM)
		{
			bzero(str, sizeof(str));
			ret = recv(fd, str, sizeof(str), 0);
			if(ret <= 0)
			{
				break;
			}
			printf("server:%s\n", str);
		}
	}	
	return 0;
}
//服务器 poll函数实现读写端口复用
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/types.h>
#include <poll.h>
int main(int argc, char *argv[])
{
	int fd = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(44445);
	addr.sin_addr.s_addr = inet_addr("192.168.1.120");
	if(bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
	{
		perror("bind");
		exit(1);
	}
	if(listen(fd, 10) < 0)
	{
		perror("listen");
		exit(1);
	}
	int newfd = accept(fd, NULL, NULL);
	printf("newfd:%d\n", newfd);
	struct pollfd fds[5];
	fds[0].fd = 0;
	fds[0].events = POLLRDNORM;
	fds[1].fd = newfd;
	fds[1].events = POLLRDNORM;
	char str[128];
	int ret;
	while(1)
	{
		poll(fds, 2, -1);
		if(fds[0].revents & POLLRDNORM)
		{
			scanf("%s", str);
			send(newfd, str, strlen(str), 0);
		}
		
		if(fds[1].revents & POLLRDNORM)
		{
			bzero(str, sizeof(str));
			ret = recv(newfd, str, sizeof(str), 0);
			if(ret <= 0)
			{
				break;
			}
			printf("server:%s\n", str);
		}
	}
	return 0;
}
4.并发服务器-tcp-poll(代码)
//并发服务器 poll实现端口复用
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/types.h>

typedef struct list
{
	int fd;
	struct list *next;
}list;

list *list_init()
{
	list *head = (list *)malloc(sizeof(list));
	head->next = NULL;
	return;
}

void list_insert(list *head, int fd)
{
	list *node = (list *)malloc(sizeof(list));
	node->fd = fd;
	node->next = head->next;
	head->next = node;
	
}
int main(int argc, char *argv[])
{
	
	int fd = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(44468);
	addr.sin_addr.s_addr = inet_addr("192.168.1.120");
	if(bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
	{
		perror("bind");
		exit(1);
	}
	if(listen(fd, 10) < 0)
	{
		perror("listen");
		exit(1);
		
	}
	
	list *head = list_init();
	list *temp;
	fd_set myset;
	int max = fd;
	char str[128];
	char ch[128];
	int num;
	int newfd;
	while(1)
	{
		bzero(str, sizeof(str));
		FD_ZERO(&myset);
		FD_SET(0, &myset);//输入
		FD_SET(fd, &myset);
		
		temp = head->next;
		while(temp)
		{
			FD_SET(temp->fd, &myset);
			temp = temp->next;
		}
		select(max+1, &myset, NULL, NULL, NULL);		
		//3.服务器发送
		if(FD_ISSET(0, &myset))
		{
			gets(str);  
			sscanf(str,"%d:%s",&num,ch);
			send(num,ch,strlen(ch),0);
		}

		if(FD_ISSET(fd, &myset))
		{
			newfd = accept(fd, NULL, NULL);
			printf("%d已连接服务器\n", newfd);
			list_insert(head, newfd);	
			max = newfd;
		}
		temp = head->next;
		while(temp)
		{
			if(FD_ISSET(temp->fd, &myset))
			{
				bzero(str, sizeof(str));
				recv(temp->fd, str, sizeof(str), 0);
				printf("client%d:%s\n", temp->fd, str);
			}
			temp = temp->next;
		}
	}	
	return 0;
}

创建时间2020.12.22

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值