----------------------day1-----------------------
FILE *fopen(char *path, char *mode)
以mode方式打开文件path(是文件路径,相对/绝对路径)
成功返回文件描述符,错误返回NULL
mode:
r:只读打开,并文件必须存在
r+:读写打开,并且文件必须存在
w:如果文件不存在创建文件,文件存在以只写的方式打开并且将文件长度截断为0。
w+:同上,不同是以读写方式打开文件
a:
a+:
以上对于文本文件
wb:只写打开或创建二进制文件
wb+:
ab+:读写打开文件,允许读或在文件末尾追加数据
fclose(FILE * pfid)
fread fwrite fgetc fputc
fgets->getline
fgets(buf, num, pfid); //如果num大于本行的字符个数将只读取
//本行的字符,如果num小于本行的字符个数
ftell:告知文件指针当前的位置
fseek():whence--SEEK_SET 文件的开头 SEEK_CUR 文件当前的位置 SEEK_END 文件末尾
_FILE_OFFSET_BITS定义在文件/usr/include/features.h
_USE_FILE_OFFSET64定义在文件/usr/include/sys/types.h
off_t 为64位 <-_USE_FILE_OFFSET64 <- _FILE_OFFSET_BITS==64
fseeko off_t 64位
ftello
gcc -D _FILE_OFFSET_BITS=64
stdin stdout stderr
FILE *tmpfile(void)
在调用这个函数的进程中创建一个文件,fclose()关闭 进程结束时自行关闭并将其删除
-------------------------------------day2---------------------------------------
fopen fgetc/fgets/fputc/fputs/fwrite/fread fclose
errno为全局变量 错误码
int fseek(FILE *pf, long offset, int whence)
定位文件的位置指针
pf:文件指针
offset:偏移
whence: SEEK_SET(文件开头) SEEK_CUR(文件当前位置) SEEK_END(文件末尾)
long ftell(FILE *pf)
从文件开头到文件当前位置指针的字节的大小
long
int fseeko(FILE *fp, off_t offset, int whence)
off_t :默认的32位
off_t定义<sys/types.h> __USR_FILE_OFFSET64定义了off_t 64
__USR_FILE_OFFSET64->_FILE_OFFSET_BITS=64
编译:-D_FILE_OFFSET_BITS=64
stdin:标准输入,连接设备是键盘
stdout:标准输出,连接设备是屏幕 缓冲
stderr:标准错误,连接设备是屏幕 没有缓冲
printf/fwrite()------>buf---------->stdout
行结束符刷新
char *fgets(char *s, int size, FILE *fp)
void setbuf(FILE *fp, char *buf)
为fp所指文件设置缓冲区为buf
作业:
实现getline
fopen/fwrite/fread/fclose--高级文件操作
linux一切都看作文件
底级文件操作:
int open(char *path, int flag, int mode)
返回:成功返回文件描述符,失败返回-1
flag: O_RDONLY O_WRONLY O_RDWR O_CREAT
mode:在文件被创建时起到作用,文件操作的权限, 数字
, 数字
S_IRWXU(rwx) S_IRUSR(r--) S_IWUSR(-w-) S_IXUSR(--x)
S_IRWXG S_IRGRP
S-IRWXO S_IROTH
int close(int pfid)
int read(int pfid, char *buf, int size)
int write(int pfid, char *buf, int size)
0表示标准输入
1表示标准输出
2表示标准错误
文件描述符分配原则:int
当前空闲并且最小的文件描述符分配给打开的文件
采样频率:每秒钟对声音采样次数
量化位:用多少字节空间表示采样
编码:
数据传输率=采样*量化位*声道
声音数据量=数据传输率*持续的时间/8
user->open(file\dsp)
********************************************
kernel->open
----------------------------------3-----------------------------
fopen fclose fread fwrite fseek fseeko ftell ftello
open read write close lseek ltell dup2 tmpfile setbuf
int fileno(FILE *fp)
将文件结构指针转化为文件描述符返回
FILE *fdopen(int fid, char *mode)
int stat(char *pathname, struct stat *buf)
int fstat(int fid, struct stat *buf)
int lstat(char *pathname, struct stat *buf)
将获取文件信息存储在buf参数中(struct stat)
区别:
stat:根据文件名获取文件信息
fstat:根据文件的文件描述符获取信息
lstat:对于普通没有区别,获取连接文件的信息
struct stat
{
}
inode: i节点
硬连接相当于备份
软连接相当于快捷方式
目录:
如果open打开一个目录,open()返回值为-1,并设置errno为EISDIR
DIR *opendir(char *dir_pathname)
struct dirent *readdir(DIR *dir)
struct dirent
{
size_t d_ino;
char d_name[NAME_MAX+1];
}
int closedir(DIR *dir)
int getopt(int argc, char **argv, char *string)
string:选项的集合
optarg:当前选项参数
optind:再一次调用getopt时下一个argv的下标
optopt:指向最后选项
string:
-:只有一个选项参数 返回1
::前面的选项后必有选项参数
ls -al /root
-l :选项
/root:选项参数
作业:
实现ls。
ls -l
ls -i
ls -a
ls -li
ls -la
ls -ia
ls -lia
time_t time(time_t *t)
1970.1.1到现在s
---------------------------------4------------------------------
struct spwd *getspnam(char *usr_name)
通过用户名称获取用户密码及相关的时间 /etc/shadow
struct spwd
{
char *sp_namp;//用户的登录名
char *sp_pwdp;//加密密码
int sp_lstch;//上一次更改口令以来经历时间
int sp_max;//经历多少天后允许被修改
int sp_warm;//密码到期警告的天数
int sp_inact;//帐户不活动之前的剩余时间
int sp_expire;//密码到期的天数
unsigned int sp_flag;
};
void setspent(void)
//循环的读取/etc/shadow下内容
struct spwd *getspent(void)
读到文件末尾返回NULL
void endspent(void)
/etc/passwd
struct passwd
{
char *pw_name;
char *pw_passwd;
__uid_t pw_uid;
__gid_t pw_gid;
char *pw_gecos;//真实用户名
char *pw_dir ; 家目录
char *pw_shell;
}
main()->return
int exit(int arg)
使整个工程结束
int _exit(int arg)
int atexit(void (*)(void))
注册退出函数,注册以栈的形式调用。exit与return结束时注册函数将被调用
进程:
进程是分配资源最小的单位。是使程序运行载体,进程运行需要一些资源(打开文件,处理信号,系统栈/内存映射等等)
PCB(进程控制块):
进程状态:
int fork()
创建父子进程,父子进程运行顺序由系统调度,父进程将代码区复制个子进程,父进程将数据区内容复制给子进程。
父进程先于子进程结束,此时子进程称为孤儿进程 系统将孤儿进程的父进程定义为init进程(1)
僵尸状态:子进程结束,父进程未结束(未结束的子进程收尸).僵尸状态的子进程的父进程结束时会对僵尸状态的子进程收尸。
僵尸进程是该进程释放所有占有的资源但未释放进程表中表项
出生fork 生活exe 死亡运行完毕 (掩埋 父亲)Z
int atexit(void(*fun)(void))
进程注册退出函数,注册函数的执行过程以栈的方式执行。
注册函数
在fork之前打开的文件,父子进程共享其文件描述符,共享文件位置指针
PCB:进程控制块
int vfork()
子进程先运行,子进程释放占有的内存空间后父进程开始运行
父子进程共享数据区
int clone(int (*pf)(void *), void *stack, int flag, void *arg)
flag:
CLONE_PARENT:创建进程为兄弟进程
CLONE_FS:父子进程使用相同的文件系统
CLONE_FILE:父子进程共享文件描述符
CLONE_VFORK:父进程挂起,直到子进程释放内存空间运行
CLONE_VM:父子进程运行于相同的内存空间
int wait(int *stat)
收尸函数,只能给任意一个子进程收尸,收尸后由阻塞状态变为运行状态
返回值为收尸的子进程ID
stat
WEXITSTATUS(stat):将接受进程的exit()中的数值返回,取出stat中低八位的值
WIFEXITED(stat):如果进程正常退出返回1。否则返回0;
WTERMSIG(stat):子进程终止的信号编号
WIFSETOPPED(stat):暂停进程时为真
WSTOPSIG(stat):子进程暂停信号的编号
int waitpid(pid_t pid, int *stat, int opt)
(pid_t
pdi>0:等待进程ID为pid的进程退出
pid=0:等同组进程的退出
pid=-1:等待任何子进程的退出
pid<-1:指定 进程组中的子进程退出,进程组id为(pid)
opt:默认为0;
WNOHANG:没有子进程退出立即返回
WUNTRACED:子进程暂停立即返回
setenv(“USER”,“U1”,1/0)
USER:是要修改的对象,U1修改后的。o为不修改,1为修改
---------------------------5------------------------------------
进程退出:
main函数中的return 3119-》main(return )
main()中最后一个}
exit()调用进程结束,刷新i/o缓冲区
_exit()调用进程结束,不刷新i/o缓冲区
int atexit(void (*fun)(void))
进程注册退出函数,注册函数执行过程以栈的方式执行。
注册函数什么会触发注册函数的执行:return exit
int getpid()获取当前进程id
***************************************************************
int wait(int *stat)
收尸函数,只能为任意一个子进程收尸。收尸后由阻塞状态变为运行状态
返回值为收尸的子进程ID
stat:
WEXITSTATUS(stat):将接受进程的exit()中的数字返回,取出stat中底8位
WIFEXITED(stat):如果进程正常退出返回1,否则返回0
WIFSIGNALED(stat):与上面相反
WTERMSIG:子进程终止的信号编号
WIFSETOPPED:暂停进程时为真
WSTOPSIG:子进程暂停信号的编号
int waitpid(pid_t pid, int *stat, int opt)
pid:
pid>0:等待进程ID为pid的进程退出
pid=0:等待同组进程的退出
pid=-1:等待任何子进程的退出
pid<-1:指定进程组中的子进程退出,进程组id为|pid|
opt:默认为0
WNOHANG:没有子进程退出立即返回
WUNTRACED:子进程暂停立即返回
作业:
通过exec()实现shell(基本命令的执行及环境变量的设置和打印)
提示:注意cd命令PWD
/*
[]#pwd
/var/ftp/upload/zhuxiaoke
[]#cd /root
[]#pwd
/root
[]#touch file /root/file
*/
fork->使进程出生
exec->进程在工作
进程消亡
wait->进程的后事
---------------------------6------------------------------------
进程组:一个或多个进程的集合 每一个进程组都一个ID
进程组中组长进程,进程组ID就是组长进程ID
父子进程统属同一进程组,父进程为该进程组组长进程
pid_t getpgrp(void)
获取调用进程所属进程组
pid_t getpgid(pid_t pid)
获取pid进程所属进程组
int setpgid(pid_t pid, pid_t pgid)
pid==0 && pgid==0:调用进程创建一个新的进程组并将调用进程设为该组组长
pid!=pgid:将pid进程移到pgid的进程组中
pid == 0&&pgid!=0:将调用进程移到pgid进程组中
int setpgrp(void)
setpgid(0,0)功能一样
会话:一个进程组或多个进程组的集合
一个会话属于一个用户登录
进程组组长进程不允许创建会话
pid_t setsid(void)
创建会话
3个摆脱:1:原会话 2:原进程组 3:原终端
守护进程:运行于后台的一种进程
用途:独立于控制终端并周期性地执行某种任务或等待处理某些事件
1 后台运行
父进程退出,子进程运行
2 脱离终端,脱离原会话,脱离原进程组
setsid()
3 改变当前工作目录
守护进程的工作目录是不能被卸载
chdir("/");
4 重设文件创建掩码
umask(0);
5 重定向标准输入、输出、错误
stdin stdout stderr->/dev/null
进程的属性:
优先级:进程的优先级数字越小优先级越大
-20~20
goto作用统一错误处理,函数内的跳转
fid = open();
if(fid < 0)
{
}
n = read(fid, )
if(n<0)
{
goto ERR;//打开这个文件,关闭文件
}
n = write()
if
ERR:
close(fid);
函数间跳转
int setjmp(jmp_buf arg)
setjmp()被调用2次,第一次正常调用setjmp()返回为0,第二次调用longjmp()返回值为longjmp()的第二个参数的值
void longjmp(jmp_buf arg, int val)
跳转到setjmp()处执行
墙钟时间:进程从开始运行到目前的为止所经历的时间
clock_t clock(void)
clock_t times(struct tms *buf)
返回系统开机以来到现在的所经历的滴答数
----------------------------7-----------------------------------
信号:软中断
中断:进程在正常运行时,中断可以产生也可以不产生。
由硬件触发,触发后调用中断处理程序去处理中断
信号的处理方式:
1 默认SIG_DFL 2 忽略SIG_IGN 3 捕捉(人为改变信号的处理方式)
ctrl+c:SIGINT
typedef void (*sig_t)(int);
sig_t signal(int signo, sig_t sig_fun)
返回值为设置之前的处理方式
----------------------------8-----------------------------------
ls shell
信号:
SIGKILL和SIGSTOP信号是不能被捕捉或忽略
SIGCHLD : 子进程在消亡时会向父进程发送该信号
闹钟:
int alarm(int s)
在调用进程中设置一个闹钟,闹钟到时后会产生信号SIGALRM
alarm(0):删除闹钟,并不产生信号SIGALRM
一个进程中只能有一个闹钟,多次设置闹钟,alarm返回上次设置闹钟的剩余时间。
返回值:0:成功设置
作用:阻塞函数设置超时时间
int kill(pid_t pid, int signo)
pid=-1:向所有进程发送信号signo
pid>0:pid表示某个进程
pid==0:向调用进程同组进程组发送信号signo
pid<0: |pid|为进程组的所有进程发送信号
int raise(int signo)
kill(getpid(), signo);
----------------------------9-----------------------------------
int sigaction(int signo,
struct sigaction *act,
struct sigaction *oact)
int setitimer()
act.sa_flags = SA_SIGINFO;
act->sa_sigaction = fun;
int sigqueue(pid_t pid, int signo, union sigval val)
union sigval
{
int sival_int;
void *sival_ptr;
};
----------------------------10-----------------------------------
临界资源:多个进程或线程访问的资源
互斥:在同一时间内仅有并只有一个进程/线程访问临界资源
条件变量:
作用:当临界资源处于特殊状态时,条件变量才会被使用。
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *attr)
pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
第一次调用
1 释放mutex互斥锁
2 将调用线程阻塞在cond条件变量
第二次调用pthread_cond_signal
1 释放cond条件变量的
2 还要在拥有mutex互斥锁变为运行
pthread_cond_signal(pthread_cond_t *cond)
激活由条件变量阻塞的线程,但每次调用只能激活一个等待线程
int pthread_cond_broadcast(pthread_cond_t *cond)
激活所由条件变量阻塞的线程
--------------------------11-------------------------------------
int pthread_create(pthread_t *thread, pthread_attr_t *attr, thread_fun , arg)
typedef struct
{
int detachstate;分离属性
int schedpolity;调度策略
int sched_param;调度参数
int inheritsched;继承属性
size_t guardsize;栈尾警戒缓冲区大小
void *stackaddr;栈的位置
size_t stacksize;栈的大小
int scope;作用域
}pthread_attr_t;
int pthread_attr_init(pthread_attr_t *attr)
int pthread_attr_destroy(pthread_attr_t *attr)
int pthread_attr_setscope(pthread_attr_t *attr, int scop)
设置绑定属性
scop: PTHREAD_SCOPE_SYSTEM绑定属性
PTHREAD_SCOPE_PROCESS非绑定属性
int pthread_attr_setdetackstate(pthread_attr_t *attr, int datashstat)
设置分离属性
PTHREAD_CREAT
线程池:
作用:减少线程创建和消亡的开销。
进程间通信:
无名管道:
int pipe(int fileds[2])
创建无名管道
0 -1
fileds: 出参
fileds[0]:为管道的读端
fileds[1]:为管道的写端
有名管道:
FIFO有一个文件与之关联
int mkfifo(char *pathname, mode_t mode)
open()阻塞函数 write/read() close()
---------------------------12------------------------------------
模块名称_功能
消息队列:-lrt
POSIX:消息是有优先级的
mqd_t mq_open(char *name,
int flag,
mode_t mode,
struct mq_attr *attr)
mq_receive()
mq_send()
mq_unlink()
inr mq_notify(mqd_t mqid, struct sigevent *notify)
struct sigevent
{
int sigev_notify;SIGEV_NONE SIGEV_SIGNAL SIGEV_THREAD
int sigev_signo;发送什么信号
union sigval sigev_value;
/*
{
int sival_int;
void *sival_ptr;
}
*/
void (*sigev_notify_function)(union sigval);线程的处理函数
pthread_attr_t *sigev_nitify_attributes;
}
System V
int msgget(key_t key, int flag)
flag: IPC_CREAT MSG_R MSG_W MSG_R/W>>3 MSG_R/W>>6
key: ftok()
int msgsnd(int msgid, void *ptr, size_t len, int flags)
struct msgbuf
{
int msg_type;
char msg_data[50];
}
int msgrcv(int msgid, void *ptr, size_t len, long type, int flag)
type:
==0:获取消息获取是最早到达消息队列的消息
>0:只能获取和该值相同的消息
<0: 只能获取小于或等于该值的消息
int msgctl(int msgid, int cmd, struct msgid_ds *buff)
cmd:
IPC_RMID:删除消息
msgsnd()和msgrcv()中len参数 数据长度,是不包含type
信号量:进程间的互斥 数值
P(等待信号量 -1) V(释放信号量 +1)
posix:
无名信号量:
int sem_init(sem_t *sem, int shared, unsigned int val)
shared:
0:进程创建的线程可以使用该信号量
非0:任意可以访问该信号量的进程都可以使用
val:信号量的初值
int sem_destroy(sem_t *sem)
P 对于信号量值-1 pthread_mutex_lock()
int sem_wait(sem_t *sem)
临界资源的操作
int sem_post(sem_t *sem)
V 对于信号量值+1 pthread_mutex_unlock()
posix 有名信号量
int *sem_open(char *name, int flag, mode_t mode, int val)
name: /
flag:O_CREAT
mode: S_IRWXU/G/O S_IR/W/XUSR S_IR/W/X/GRP S_IR/W/XOTH 777
val:信号量的初值
int sem_close(sem_t *sem)
int sem_unlink(char *name)
system V
信号量集
int semget(key_t key, int nsems, int flags)
nsems:信号量集中信号量的个数
flags:SEM_R SEM_A IPC_CREAT IPC_EXCL
int semop(int semid, struct sembuf op[nops], size_t nops)
op:指向数组
nops:数组成员个数
struct sembuf
{
short sem_num;信号集中某个信号量的下标 0~nsems-1
short sem_op;对于某个信号量的操作 负数:获取信号量-n(1)
正数:释放信号量+n(1)
short sme_flg;SEM_UNDO 0
}
int semctl(int semid, int semnum, int cmd, union semun arg)
GETALL:获取信号量集中每个信号量的值,并存放到arg
SETVAL:设置某个信号量的初值为arg
GETVAL:获取某个信号量的当前值
GETPID:最后一个执行semop()进程id
union semun
{
int val;setval
short *arg;
struct semid_ds *buf;
};
void *mmap(void *addr,//NULL
size_t len,
int prot ,
int flags,
int fd,
off_t offset//起始位置:文件开头+offset)
----------------------------13-----------------------------------
共享内存:
posix:
int shm_open(char *name, int flag, mode_t mode)
name: 共享内存的名称 "/"
flag:O_RDONLY O_WRONLY O_CREAT O_EXCL
mode: flag为O_CREAT 0777 S_IRWXU/G/O
返回:共享内存的描述符 -1
int ftruncate(int shm_id , int size)
mmap()
int shm_unlink(char *unlink)
system V
int shmget(key_t key, size_t size, int flag)
key:
size:共享内存大小,字节
flag:O_CREAT 打开:0
返回:共享内存描述符 -1
void *shmat(int shmid, void *shareaddr, int flag)
shareaddr:NULL
非NULL:flag设置SHM_RND,shareaddr
flag: 0 SHM_RND(强迫将内存大小设定为页面大小)
int shmdt(void *share_addr)
断开映射
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
cmd: IPC_STAT:获取共享内存信息
IPC_RMID:
***********************************************************
字节序:
机字节序:小端对齐
网络字节序:大端对齐
htonl htons ntohl ntohs
ip地址:
字符串:192.168.3.254
数值:in_addr_t->uint32_t
地址结构体
struct in_addr
{
in_addr_t s_addr;
};
字符串-》数值
int inet_aton(char *ip, struct in_addr *addr)
in_addr_t inet_addr(char *ip)
数值->字符串
char *inet_ntoa(struct in_addr *addr);
OSI模型:
应用
表示
会话 user
******************************
传输 tcp/udp kernel
网络 ip
数据链路
物理
tcp:
int socket(int family, int socktype, int protocol)
创建套接字
family:协议族 AF_INET AF_INET6
type:SOCK_STREAM(TCP) SOCK_DGRAM(UDP) SOCK_RAM
protocol:0 PROTO_TCP PROTO_UDP PROTO_ARP
返回:套接字描述字 -1
int bind(int sockfd , struct sockaddr *addr, int addrlen)
调用该函数进程只能接收的报文为目的地址为帮定地址的报文
地址通用结构体
struct sockaddr
{
unsigned short sa_family;
char sa_data[14];
};
套接字地址结构体
struct sockaddr_in
{
short sin_family;//AF_INET
unsigned int sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
};
int listen(int sockfd, int num)
num:设置完成连接的队列的长度
int connect(int sockfd, struct sockaddr *addr, socklen_t len)
发起3次握手连接
addr:连接方的ip地址
len:ip地址长度
int accept(int sockfd, struct sockaddr *addr, socklen_t *len)
server(被动) client(主动)
socket() socket()
bind()
listen() connect()
accept()
write/read read/write
close() close()
-----------------------------14----------------------------------
socket()
bind()
select:
轮询式(0~MAXFID)的监听文件描述符,并且每监听一次所监听的文件描述将失效
fd_set:
int select(int nfid,
fd_set *rdfid,
fd_set *wrfid,
fd_set *exefid,
struct timeval *timeout/*0*/)
{
long tv_sec;
long tv_usec;
}
FD_ZERO(fd_set *set)
FD_SET(int fd, fd_set *set)
FD_CLR(int fd, fd_set *set)
FD_ISSET(int fd, fd_set *set)
poll:效率和select相同
int poll(struct pollfd fds[], nfds_t nfds, int outtime)
struct pollfd
{
int fd;
short events;感兴趣的事件
short revents;实际发生的事件
};
事件:
POLLIN 可读
POLLOUT 可写
POLLERR 出错
epoll:
优点:
1 没有最大并发连接的限制,/proc/sys/fs/file-max
2 效率提升,只管活跃连接,连接数目有关系
int epoll_create(int size)//1000 10000
epoll句柄
size:用来告知kernel最多可以监听的数目
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *ev)
epfd:epoll_create()返回值
op:
EPOLL_CTL_ADD:将fd注册到epfd
EPOLL_CTL_MOD:修改已注册fd监听事件
EPOLL_CTL_DLE:将fd从epfd中删除
fd:
ev:
struct epoll_event
{
__uint32_t events;EPOLLIN EPOLLOUT EPOLLLT EPOLLET(文件描述符就绪,只通知一次)
epoll_data_t data;
{
void *ptr;
int fd;
}
}
int epol_wait(int epfd, struct epoll_event *ev, int maxevs, int timeout)
close(confd/sockfd);
只是关闭文件描述符,但是tcp连接依然连接,其他进程还可以进行通信
所有拥有文件描述符进程都关闭后,连接才会被释放
int shutdown(int sockfd, int howto)
howto:
SHUT_RD关闭读这一半
SHUT_WR关闭写这一半
SHUT_RDWR
-----------------------------15----------------------------------
udp:
int socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
int bind()
ssize_t recvfrom(int sockfd,
void *buf,
size_t len,
int flags,//0 MSG_DONTROUTE MSG_OOB
struct sockaddr *addr,
size_t *addr_len)
ssize_t sendto(int sockfd,
void *buf,
size_t len,
int flag,
struct sockaddr *addr,
size_t addr_len)
connect()
广播:增加网络负担
192.168.3.255
ipv4 ipv6 tcp udp
单播 1 1 1 1
广播 1 0 0 1
组播:一个或多个ip地址加入到一个组播地址
224.0.0.0~239.255.255.255
224.0.0.1
224.0.0.2
setsockopt(sockfd, IPPROTO_IP, cmd, &arg, sizeof(arg))
cmd: arg
IP_ADD_MEMBERSHIP struct ip_mreq
{
struct in_addr imr_multiaaddr;//组播地址
struct in_addr imr_infterface;//本地ip地址
}
IP_DROP_MEMBERSHIP struct ip_mreq
------------------------------16---------------------------------
字节序:
htonl ntohl 主机字节序转化成网络字节序,网络字节序转化成主机字节序
htons ntohs
h:主机字节序
n:网络字节序
l:四字节(32位)
s:两字节(16位)
ip地址的表示类型
192.168.2.254 字符串的表示
还有一种是数值表示
int inet_aton(char *ptr, struct in_addr *addr)
将字符串地址转化成数值地址
成功返回1,失败返回0
ptr:
struct in_addr
{
unsignet long in_add_t s_addr;
}
unsigned long int inet_addr(char *ptr)
将字符串地址转化成数值地址,直接返回数值地址
char *inet_ntoa(struct in_addr addr)
将数值地址转化成字符串地址
int inet_pton(int family, char *ptr, void *add)
将字符串地址转化成数值地址
family:指定了ip协议的版本 AF_INET(ipv4) AF_INET6(ipv6)
prt:指向了字符串地址的首地址
addr:
char *inet_ntop(int family, void *addr ,char *ptr, size_t len)
将数值地址转化成ip地址
family:同上
addr:数值ip地址的地址
ptr:存储字符串ip地址的首地址
len: 转化成字符串地址的长度
ipv4(16位) INET_ADDRSTRLEN
ipv6(46位) INET6_ADDRSTRLEN
网络连接时用的结构体 (主要使用的结构体)
struct sockaddr_in
{
short sin_family; 地址族,一般都是AFINET (ipv4)
unsigned int sin_port; 端口号
struct in_addr sin_addr; 数值ip地址
unsigned char sin_zero[8]; 保留的
}
通用地址结构体
struct sockaddr
{
unsigned short sa_family;
char sa_data[14];
}
OSI]
*****************
1.物理层
2.数据链路
设备驱动程序和硬件
*****************
3.网络 ipv4 ipv6
***********************************
4.传输层 tcp udp 内核
****************************
5. 会话 用户
6. 表示
7. 应用
socket套接字 socket也是一种文件类型
int socket(int family, int type, int protocol)
创建套接字函数
family:协议组 AF_INT(ipv4协议) AF_INET6 AF_LOCAL(UNIX域协议)
AF_ROUTE 路由套接字 AF_KEY密钥套接字
type: SOCK_STREAM 字节流套接口
SOCK_DGRAM数据报套借口
protocol: 一般设为0, IPPROTO_TCP IPPROTO_UDP IPPROTO_SCTP
int bind(int sockfd, struct sockaddr *addr, int addrlen)
将addr中的地址和端口与sockfd绑定
返回值0 , -1
仅在TCP协议中调用,只在服务器端调用
int listen(in sockfd, int backlen)
backlen:内核为此套接口规定的排队的最大连接数
int accept(int sockfd, struct sockaddr *addr, socklen_t *len)
tcp服务器端调用
等待客户端的连接
addr:客户端ip地址首地址
len:客户端ip地址长度
返回一个新的描述符
仅限于客户端调用
int connect(int sockfd, struct sockaddr *seraddr,
int addrlen)
客户端与服务器端连接,激发三次握手
server
socket()---> bind()-->listen()-->accept()-->read()/write()---------->close()
^ ^
client | |
socket()------------------------>connect()-->write()/read()->close()
------------------------------17---------------------------------
select:
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exefds, struct timeval *timeout)
nfds: maxfds+1 所有监控的文件描述符中最大的值加1
readfds:
writefds:
exefds:
fd_set
FD_ZERO(&readfds) 将其清零
FD_SET(fd, &readfds) 将一个文件描述符加入到这个句柄当中去
FD_CLR(fd, &readfds)将一个文件描述符从句柄中删除
FD_ISSET(fd, &readfds) 测试是文件描述符在句柄的监视下是否可读/可写 大于0可
timeout: NULL 一直阻塞 如果将struct timeval={0,0}立即返回
poll:
int poll(struct pollfd fd[], nfds_t nfds, int timeout)
struct pollfd
{
int fd; /* file descriptor */
short events; /* requested events */ 感兴趣的事件,在监视前设置
short revents; /* returned events */ 实际发生的事件,在监视到事件发生,测试那个文件发生了什么事件
};
感兴趣的事件:POLLIN(可读普通或者优先级数据)
POLLRDNORM(普通数据的可读)
POLLOUT(普通可写)
POLLNVAL(描述符不是一个可打开的文件)
POLLERR(出错)
timeout: INFTIM 就是-1 单位是毫秒
int setsockopt(int sockfd,
int level,
int optname,
void *optval,
socklen_t *optlen)
设置套接字的属性
level = SOL_SOCKET IPPROTO_IP
optname = SO_REUSEADDR
1.一个地址和端口被一个套接字绑定,并且当前的套接字处于TIME_WAIT状态,
另一个套接字可一个绑定同一端口和地址 服务器端使用
2.同一端口上同一服务器多进程,但ip不同
3.允许地址和端口重复被绑定。 使用于UDP的多播
int onoff = 1;(启用不启用)
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &onoff, sizeof(int));
启用了这个属性
int setsockopt(int s,
int level,
int optname,
const void *optval,
socklen_t optlen);
获取套接字的属性
int shutdown(int sockfd, int howto)
激发TCP连接正常终止的函数
howto: SHUT_RD SHUT_WR(关闭了一方的读和写) SHUT_RDWR
close(sockfd) close(connfd) 关闭连接 释放套接字上的地址和端口
struct hostent *gethostbyname(char *hostname)
通过主机名获取ip地址
struct hostent
{
char *h_name; //主机规范名
char **h_aliases; //多个主机别名
int h_addrtype; //ip地址的类型(包括ipv4 和 ipv6)
int h_length; //ip地址的长度
char **h_addr_list; //ip地址网络序
}
struct hostent *gethostbyaddr(char *addr, size_t len, int family)
根据二进制ip地址获取主机名
addr: ip地址 (char *)addr.sin_addr
len: AF_INET(4) AF_INET6(16)
-------------------------------18--------------------------------
UDP无连接的不可靠的数据传输协议
客户端与服务器端连接后,一端只是再发送数据,不再确认是否发送成功。
server client:
socket()
bind()
recvfrom() socket()
sendto()
一直阻塞,直到有数据输入
处理请求
sendto() recvfrom()
ssize_t recvfrom(int sockfd, void *buf, size_t nbytes,
int flag, struct sockaddr *from,
socklen_t *addrlen)
sockfd: 从该套接字接受数据
buf:缓冲区
nbytes:缓冲区长度
flag:一般设为0
MSG_DONTROUTE:
MSG_DONTWAIT:非阻塞
from: 存放对端的地址
addrlen: 存放对端的地址长度
errno:
EAGAIN:套接字标记为非阻塞,但接受被阻塞或超时
EBADF:socket不是有效的描述符
ECONNREFUSE:远程网络拒绝连接
ssize_t sendto(int sockfd, void *buf, size_t nbytes,
int flag, struct sockaddr *to,
socklen_t addrlen)
发送消息
to:接收端的地址
addrlen: 接收端地址长度
struct ifreq
{
char ifrn_name[IFNAMSIZ];
struct sockaddr ifru_addr;
struct sockaddr ifru_netmask;
#define ifr_name ifr_ifrn.ifrn_name;
}
------------------------------19---------------------------------
单播:ipv4 ipv6 tcp udp
多播:可选 支持 不支持 支持
广播:支持 不支持 不支持 支持
广播的地址:
192.168.2.255 向子网发送报文
255.255.255.255 向整个网络发送报文 (这两个路由器都不转发
广播程序设计:
service:
1. socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
2. setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, opt, sizeof(int));
opt为1 开启 为0 关闭 int opt (开启广播功能)
3. 设定ip地址 x.255
4. sendto()
client:
1.socket
2.设定连接地址 x.255
bind
3. recv sendto
多播:
224.0.0.0 - 239.255.255.255 多播地址范围
224.0.0.1 所有具有组播功能的主机和路由器
224.0.0.2 路由器组
224.0.0.0 - 224.0.0.225 被保留的多播地址 (路由器不转发)
setsockopt()的多播选项
IP_ADD_MEMBERSHIP 加入一个多播组 struct ip_mreq
IP_DROP_MEMBERSHIP 离开一个多播组 struct ip_mreq
IP_BLOCK_SOURCE 在一个已加入的多播组上阻塞 struct ip_mreq_source
IP_UNBLOCK_SOURCE 将阻塞的开通struct ip_mreq_source
struct ip_mreq
{
struct in_addr imr_multiaddr;
struct in_addr imr_interface;
};
struct ip_mreq_source
{
struct in_addr imr_multiaddr; //ipv4地址
struct in_addr imr_interface; //本地地址
struct in_addr imr_sourceaddr; //ipv4原地址
}
#route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0
添加路由,多播时必须设定的
1. sockfd = socket(AF_INET, SOCK_GRAM, 0);
2. 设定地址,bind()
3. setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &opt, sizeof(int))设置一个环回地址有效(可有可无)给自己也发送报文
4.加入多播组
struct ip_mreq mreq
mreq.imr_multiaddr = inet_addr("224.0.0.88");
mreq.imr_interface.s_addr = inet_addr("192.168.2.11"); 把这个地址加入多播组 inet_addr(INADDR_ANY);将本机地址加入多播组
setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
---------------------------20-----------------------
Unix域套接字: X11
在单个主机上执行客户/服务器通信
TCP/UDP地址的定义
struct sockaddr_in
{
sin_port;
sin_family;
sin_addr->s_addr;
}
struct sockaddr
Unix域套接字结构体
struct sockaddr_un
{
sa_family sun_family; //AF_LOCAL
char sun_path[14]; //sum_path[0] = '\0'等价于 INADDR_ANY
}
socket(AF_);//面向字节流
//面向数据流
int socketpair(int family, //AF_LOCAL
int type, //SOCK_STREAM SOCK_DGRAM
int protocol, //必须是 0
int sockfd[2]) 双工通信
原始套接字:
1.可以读写 ICMPV4 IGMPV4 ICMPV6报文
2.可以读写内核不处理的协议字段的ipv4数据报文
3.可以自行构造ipv4报文首部
sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
setsockopt(sockfd,
IPPROTO_IP,
IP_HDRINCL,
&on, sizeof(int));
/usr/include/netinet/ip.h
/usr/include/netinet/ip_icmp.h
--------------------------------21--------------------------
Dos:
/usr/include/netinet/tcp.h
struct tcphdr
{
u_int16 source;
u_int16 dest;
}
struct sockaddr_ll
{
un_short sll_family; // AF_PACKET
un_short sll_protocol; // ARP 0x0806<==>ETH_P_ARP ETH_P_IP<==>0x0800
int sll_ifindex; // 接口类型 IF_PORT_10BASET
un_short sll_hatype; // 报文的类型
un_char sll_pktypes; // 包的类型
un_char sll_halen; // 地址的长度
un_char sll_addr[8]; // MAC地址
}
|<-------------------以太网首端--------------------------->|
以太网目的地址(6字节) 以太网源地址(6) 贞类型(2)
|<-------------------ARP请求/响应报文------------
硬件地址(2) 协议地址(2) 硬件地址长度(1) 协议地址类型长度(1) op(2)
发送端以太网地址(6) 发送端IP地址(4) 目的以太网地址(6) 目的端IP地址(4)
请求报文无
------------------------------------------------------------------------------>|
以太网目的地址为12个f(6个字节) 为广播报文
SCTP: