apue-笔记

来源:互联网 发布:ar软件下载 编辑:程序博客网 时间:2024/05/16 05:29

----------------------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:






原创粉丝点击