Linux 应用开发
文件和IO
- 文件
- 类型
- 普通 目录d 字符设备c 块设备b 管道p 套接字s 符号链接l
ls -l
stat() fstat() lstat
文件信息
- 符号链接
<unistd.h>
unlink()
link()
创建移除硬链接symlink()
readlink()
创建和读取软链接
- 权限
chown() lchown() fchown()
改变属主chmod() fchmod()
改文件权限
- 长度和截取
- 空洞文件
truncate()
ftruncate()
截取文件
- 更改文件名
rename()
- 文件时间戳
utime() utimes() futimes() lutimes()
- 类型
- 目录
mkdir()
rmdir()
创建删除opendir() readdir()
打开和读取dirname() basename()
路径分解
- 文件系统
- 磁盘~(ntfs ext4)
- 网络~(nfs samba)
- 虚拟~(vfs)
- IO
- 标准io相比文件io多了缓存区以减少系统调用次数
- 实践上一般用
fopen
打开普通文件,open
打开设备文件 - FILE* 流指针
- 打开
fopen() fdopen() freopen()
- 预定义~ 标准输入(键盘)输出(终端) 错误输出(终端)(无缓存)
fclose()
程序结束时自动关闭FILE *fp; if((fp=fopen("txt","w"))==NULL){} fclose(fp);
- 打开
- 错误输出
perror("message")
strerror(errno)
errno是系统自带错误码变量 - 流的读写
fputc() fgetc() fputs(char*,FILE*)
字符读写fgets(char*, int size, FILE*)
字符串读写fwrite() fread()
二进制(传指针)读写
- 从输入输出获取
while((ch=fgetc(stdin))!=EOF){fputc(ch,stdout)}
getchar() putchar()
while(fgets(buf,size,stdin)!=NULL){fputs(buf,stdout)}
gets() puts()
- 缓存
- 全缓(文件)(4k) 行缓(标准输入输出)(1K) 不缓(错误输出)
- 刷新条件 写满
fflush()
程序退出\n
- 更改全/行缓存
setbuf() setvbuf()
- 流的定位
fseek() ftell()
去/查定位 - 格式化输入输出
printf() fprintf() sprintf()
scanf() fscanf() sscanf()
- 标准/文件/字符串
- 文件IO
- 打开关闭
int fd = open(path, flag, [mode])
0<fd<1023
int close(int fd)
- 读写
write(fd, (void *)buf, size)
read(fd, buf, size)
- 定位
lseek(fd, offset, whence)
偏移后再写就会得到空洞文件 - 锁
- 上建议性锁
lockf()
- 锁控制
int fcntl(fd, cmd, flock)
flock结构体略
- 上建议性锁
- 生产消费模式实例
- 打开关闭
c
#include "fcntl.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "unistd.h"
const char* fifo_file = "./myfifo";
char buf[10];
int product() {
int fd;
unsigned int type, start, count, size;
static unsigned int counter = 0;
if ((fd = open(fifo_file, O_RDWR | O_CREAT | O_APPEND, 0664)) < 0) {
perror("error");
return 0;
}
type = 1;
switch (type) {
case 1:
start = 'a';
count = 26;
break;
case 2:
start = '0';
count = 10;
break;
default:
return 0;
}
sprintf(buf, "%c", (start + counter));
counter = (counter + 1) % count;
lock_set(fd, F_UNLCK);
close(fd);
return 1;
}
int main() {
int t = 1;
int c = 10;
while (c--) {
if (!product()) break;
sleep(t);
}
return 0;
}
c
#include "fcntl.h"
#include "lock_set.c"
#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
const long file_size = 100 * 1024 * 1024;
const char* fifo = "./myfifo";
const char* temp_file = "./tmp";
int customing(const char* myfifo, int need) {
int fd;
char buf;
int cc = 0;
if ((fd = open(myfifo, O_RDONLY)) < 0) {
perror("error");
return -1;
}
lseek(fd, SEEK_SET, 0);
while (cc < need) {
while ((read(fd, &buf, 1) == 1) && (cc < need)) {
fputc(buf, stdout);
cc++;
}
}
fputs("\n", stdout);
close(fd);
return 0;
}
int myfilecopy(const char* sourse,
const char* dest,
int offset,
int count,
int mode) {
int in, out;
int counter = 0;
char buff;
if ((in = open(sourse, O_RDONLY)) < 0) {
perror("error");
return -1;
}
if ((out = open(dest, O_RDWR | O_CREAT | O_TRUNC, 0664)) < 0) {
perror("error");
return -1;
}
lseek(in, offset, SEEK_SET);
while ((read(in, &buff, 1) == 1) && (counter < count)) {
write(out, &buff, 1);
counter++;
}
close(in);
close(out);
return 0;
}
int custom(int need) {
int fd;
customing(fifo, need);
if ((fd = open(fifo, O_RDWR)) < 0) {
perror("error");
return -1;
}
// 为了模拟所作的平移
lock_set(fd, F_WRLCK);
myfilecopy(fifo, temp_file, need, file_size, 0);
myfilecopy(temp_file, fifo, 0, file_size, 0);
lock_set(fd, F_UNLCK);
unlink(temp_file);
close(fd);
return 0;
}
int main() {
int customer = 10;
if (customer > 0)
custom(customer);
return 0;
}
c
#include "fcntl.h"
#include "stdio.h"
#include "stdlib.h"
#include "sys/stat.h"
#include "sys/types.h"
#include "unistd.h"
int lock_set(int fd, int type) {
struct flock lock;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
lock.l_type = type;
lock.l_pid = -1;
fcntl(fd, F_GETLK, &lock);
lock.l_type = type;
if ((fcntl(fd, F_SETLKW, &lock)) < 0) {
return -1;
}
return 0;
}
进程线程
- 进程
- 状态
- 运行态 睡眠态 停止态 僵尸态 消亡态
- 进程组和会话组
- 优先级
- 调度
- 时间片结束(RR) 自愿放弃 进程终止 优先级抢占
- 虚拟内存
- 布局递增 程序代码 初始化数据 BBS 堆 共享库 栈 命令行参数和环境变量
- 创建
fork()
vfork()
if(pid<0){error}else if(pid==0){子进程}else{父进程}
- 进程id
getppid()自身 getppid()父进程id
- 执行另外的进程
execl(path,arg...)``execlp(file,arg...)
execle(path,arg...,环境变量)
execv(path,[arg])
execvp(file,[arg])
execvpe(file,[arg],环境变量)
- 终止进程
exit() _exit()
- 孤儿进程 父进程先结束了 init进程成为义父
- 僵尸进程 程序退出却没有释放资源 子进程退出父进程没退出时产生
- (父)等待
wait(子进程退出时的return) waitpid(pid,status,0/WHOHANG)
- 守护进程
- 创建子进程,父进程退出
fork() exit(0)
- 子进程创建新会话
setsid()
- 改变当前工作目录
chdir(path)
- 重设文件权限掩码
umask(0)
- 关闭文件描述符号
close(num)
- 创建子进程,父进程退出
- 系统日志 syslog 用于守护进程输出信息
openlog(name,option, facility) syslog(priority,string) closelog()
- 状态
- 线程
pthread.h
- 创建
pthread_create()
- 退出
- 线程
return
- 自己
pthread_exit()
- 他人
pthread_cancel()
- 任意线程
exit()
全终止 - main函数
return
全终止
- 线程
- 等待
pthread_join(thread, rt)
等待指定线程终止接收返回状态 - 分离
pthread_detach(thread)
不关心返回状态,线程自行终止和清理pthread_attr_init/destroy(*attr)
pthread_attr_setdetachstate()
创建即分离
- 取消
pthread_cancel(thread)
向进程发送取消请求pthread_setcancelstate(state,oldState)
取消状态设置pthread_setcanceltype()
设置~取消类型pthread_testcancel()
为当前线程设置取消点
- 通信 使用全局变量即可
- 互斥锁
- 创建和释放
pthread_mutex_init()
pthread_mutex_destroy()
- 上锁和解锁
pthread_mutex_lock()
pthread_mutex_unlock()
pthread_mutex_trylock(mutex)
若占用报错而不等待pthread_mutex_timedlock(mutex,timeout)
设置等待时间
- 创建和释放
- 死锁
- 在线程中对同一互斥锁多次加锁
- 多个线程对多个锁交叉使用
- 持有互斥锁的线程被其他线程取消
pthread_cleanup_push/pop()
向清理函数栈添加和移除清理函数 以规避死锁
- 互斥锁属性
pthread_mutexattr_getpshared/setpshared()
获得/设置互斥锁属性- 一个进程内两个线程间互斥(默认) 不同进程线程互斥
pthread_mutexattr_gettype/settype()
设置互斥锁类型- 标准~ 检错~ 递归~(recursive)(同一线程多次上锁)
- 信号量
semaphore.h
- 创建销毁
sem_init/destory(sem)
- 减一
sem_wait(sem)
sem_trywait(sem)
不阻塞sem_timewait(sem, timeout)
时间限制 - 加一
sem_post(sem)
- 获取
sem_getvalue(sem, save)
- 创建销毁
- 条件变量
pthread.h
类似通知- 创建销毁
pthread_cond_destroy/init(cond)
- 唤醒
pthread_cond_broadcast/signal(cond)
广播和单播 - 等待
pthread_cond_timedwait/wait(cond, mutex, [time])
- 用法
- 主函数 初始化条件变量和互斥锁 创建线程以及join 销毁所和条件变量
- 一个线程 循环上锁解锁给通知
- 一个线程 循环上锁 等通知运行解锁
- 创建销毁
- 线程池
- 创建
c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
// 定义互斥锁
pthread_mutex_t mutex;
// 全局变量
int counter = 0;
// 线程函数
void *thread_function(void *arg) {
// 加锁
pthread_mutex_lock(&mutex);
// 对全局变量进行操作
counter++;
printf("Thread %ld: counter = %d\n", (long)arg, counter);
// 解锁
pthread_mutex_unlock(&mutex);
return NULL;
}
int main() {
// 初始化互斥锁
pthread_mutex_init(&mutex, NULL);
// 创建线程数组
pthread_t threads[10];
// 创建并启动线程
for (long i = 0; i < 10; i++) {
pthread_create(&threads[i], NULL, thread_function, (void *)i);
}
// 等待线程结束
for (long i = 0; i < 10; i++) {
pthread_join(threads[i], NULL);
}
// 销毁互斥锁
pthread_mutex_destroy(&mutex);
return 0;
}
c
#ifndef _POOL_H
#define _POOL_H
#include "assert.h"
#include "pthread.h"
#include "stdio.h"
#include "stdlib.h"
#include "sys/types.h"
#include "unistd.h"
// struct worker等同于 Worker
typedef struct worker {
void* (*process)(void* arg);
void* arg;
struct worker* next;
} Worker;
typedef struct {
pthread_mutex_t lock;
pthread_cond_t cond;
Worker* head;
int shutdown;
pthread_t* tid;
int max_num;
int queue_size;
} Pool;
extern void pool_int(int max_num);
extern void* thread_routine(void* arg);
extern void* myprocess(void* arg);
extern int pool_add_worker(void* (*process)(void* arg), void* arg);
extern int pool_destroy();
#endif
c
#include "pool.h"
static Pool* pool = NULL;
void ppinfo() {
printf("0x%x", pthread_self());
}
void* thread_routine(void* arg) {
pp();
while (1) {
pthread_mutex_lock(&(pool->lock));
// 队列空
while (pool->queue_size == 0 && !pool->shutdown) {
pp();
pthread_cond_wait(&(pool->cond), &(pool->lock));
}
// 摧毁
if (pool->shutdown) {
pthread_mutex_unlock(&(pool->lock));
pp();
pthread_exit(NULL);
}
pp();
assert(pool->queue_size != 0);
assert(pool->head != NULL);
pool->queue_size--;
Worker* worker = pool->head;
pool->head = worker->next;
pthread_mutex_unlock(&(pool->lock));
((*worker->process))(worker->arg);
free(worker);
worker = NULL;
}
pthread_exit(NULL);
}
void pool_init(int max_num) {
pool = (Pool*)malloc(sizeof(Pool));
pthread_mutex_init(&(pool->lock), NULL);
pthread_cond_init(&(pool->lock), NULL);
pool->head = NULL;
pool->max_num = max_num;
pool->queue_size = 0;
pool->shutdown = 0;
pool->tid = (pthread_t*)malloc(max_num * sizeof(pthread_t));
for (int i = 0; i < max_num; i++)
pthread_create(&(pool->tid[i]), NULL, thread_routine, NULL);
}
// 测试
void* test_process(void* arg) {
pp();
sleep(1);
return NULL;
}
// 添加
int pool_add_worker(void* (*process)(void* arg), void* arg) {
Worker* worker = (Worker*)malloc(sizeof(Worker));
worker->process = process;
worker->arg = arg;
worker->next = NULL;
pthread_mutex_lock(&(pool->lock));
Worker* member = pool->head;
if (member != NULL) {
while (member->next != NULL) {
member = member->next;
}
member->next = worker;
} else {
pool->head = worker;
}
assert(pool->head != NULL);
pool->queue_size++;
pthread_mutex_unlock(&(pool->lock));
pthread_cond_signal(&(pool->cond));
}
// 删除
int pool_destroy() {
if (pool->shutdown)
return -1;
pool->shutdown = 1;
pthread_cond_broadcast(&(pool->cond));
for (int i = 0; i < pool->max_num; i++) {
pthread_join(pool->tid[i], NULL);
}
free(pool->tid);
Worker* head = NULL;
while (pool->head != NULL) {
head = pool->head;
pool->head = pool->head->next;
free(head);
}
pthread_mutex_destroy(&(pool->lock));
pthread_cond_destroy(&(pool->cond));
free(pool);
pool = NULL;
return 0;
}
c
#include "pool.h"
int main() {
pool_init(3);
sleep(1);
int* working_num = (int*)malloc(sizeof(int) * 10);
for (int i = 0; i < 10; i++) {
working_num[i] = i;
pool_add_worker(myprocess, &working_num[i]);
sleep(5);
pool_destroy();
free(working_num);
return 0;
}
}
进程通信
- 管道使用上类似文件 本质是内核空间内存区域
- 无名管道
unistd.h
- 创建
pipe(int pipefd[2])
pipefd[0/1]
分别为读端和写端 - 只用于亲缘关系进程间通信
- 单工 有固定的读写端
- 读写采用
read/write
等文件io方法操作fd - 不支持
lseek()
进行定位 - 读取后消除
- 大小固定(64k),写满后阻塞(<4k)
- 读端关闭时写入,管道破裂,进程退出
close(fd[0])
- 写关闭时可读,无数据时读操作阻塞
- 创建
- 有名管道
sys/types.h
sys/stat.h
- 创建
mkfifo(name, 权限)
不应重复创建if(mkfifoi("fifo",0664)<0){}
if(errno==EEXIST)fd=open("fifo",O_RDWR)
- 可以用终端创建
mkfifo name
- 销毁
system("rm fifo")
- 用
fd = open("fifo", mode)
打开后使用 - 可以用于不相关进程通信
- 也是内核内存,不可
lseek()
- 先进先出
- 文件io方式使用
- 无数据时读操作阻塞 空间已满时写操作阻塞
- 创建
- 信号 异步通信 类似中断
signal.h
- 处理方式 忽略 捕捉默认
- 信号名称
kill -l
可以看到SIGUSR1
等等可以自定义
- 信号注册
typedef void (*sighandler_t)(int)
typedef void (*)(int) sighandler_t
sighandler_t signal(sigName, sighandler_t handler)
!= SIG_ERR- 进阶
int sigaction(sigName, act, oldact)
act是包含处理方式的sigaction结构体
- 信号发送
- 发给进程
int kill(pid, sigName)
- 发给自己
raise(sigName)
- 发给进程
- 定时器信号
unistd.h
int alarm(seconds)
发出SIGALRM
信号 返回剩余时间或0
- 消息队列 可以双向通信
sys/ipc.h
sys/msg.h
key_t ftok(path, 混淆)
生成keyint msgid = msgget(key, msgflg)
创建队列- IPC_CREAT IPC_EXCL 0664
msgsnd(msgid,msgbuf* msg, size, 是否阻塞(0/IPC_NOWAIT))
消息发送struct msgbuf{long mtype;char mtext[1];}
msgrcv(msgid, msg, size, 第n+1个消息, 0/IPC_NOWAIT)
接收消息msgctl(msgid, cmd, buf)
消息控制- IPC_STAT 获取属性 IPC_SET 设置属性 IPC_RMID 删除消息队列
- 终端
ipcs -q
- 共享内存
sys/shm.h
- 最为高效 需要搭配互斥机制使用
int shmid = shmget(key/IPC_PRIVATE, size, IPC_CREAT/IPC_EXCL/0664)
创建shmat(shmid, addr(NULL), 0(读写)/SHM_RDONLY(仅读))
映射到进程的虚拟地址空间shmdt(addr)
断开映射关系shmctl(shmid, cmd(IPC_STAT/IPC_SET/IPC_RMID), struct shmid_ds *buf)
控制
- 信号灯
sys/sem.h
- 创建
int semid = semget(key, nsems, IPC_CREAT/IPC_EXCL/0664)
- 控制
semctl(semid, semnum, cmd, union semun)
- ipcstat ipcset ipcrmid setval getval
- PV操作
semop(semid, struct sembuf *sops, 操作信号量的个数)
struct sembuf{}
unsigned short sem_num
编号short sem_op
1/-1 加减short sem_flg
0/SEM_UNDO(进程退出时自动释放信号量)
- 创建
c
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
int main() {
int fd;
char buf[128] = "";
if (mkfifo("fifo", 0664) < 0) {
if (errno == EEXIST) {
fd = open("fifo", O_RDWR);
printf("%d\n", fd);
}
} else {
fd = open("fifo", O_RDWR);
printf("%d\n", fd);
}
while (1) {
fgets(buf, 128, stdin);
buf[strlen(buf) - 1] = '\0';
write(fd, buf, strlen(buf));
// read(fd, buf, 128);
if (strncmp(buf, "quit", 4) == 0) {
break;
}
}
return 0;
}
c
#include "errno.h"
#include "signal.h"
#include "stdio.h"
#include "string.h"
#include "sys/ipc.h"
#include "sys/msg.h"
#include "sys/types.h"
#define SIZE sizeof(struct msgbuf) - sizeof(long)
struct msgbuf {
long mtype;
char buf[128];
};
int main() {
key_t key;
if ((key = ftok(".", 'a')) < 0) {
perror("error");
return -1;
}
int msgid;
struct msgbuf msg_snd, msg_rcv;
if ((msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0664)) < 0) {
if (errno != EEXIST) {
perror("error");
return -1;
} else {
msgid = msgget(key, 0664);
}
}
pid_t pid;
pid = fork();
if (pid < 0) {
perror("error");
return -1;
} else if (pid) {
while (1) {
msgrcv(msgid, &msg_rcv, SIZE, 200, 0);
if (strncmp(msg_rcv.buf, "quit", 4) == 0) {
kill(pid, SIGKILL);
goto err;
}
printf("%s\n", msg_rcv.buf);
}
} else {
while (1) {
msg_snd.mtype = 100;
fgets(msg_snd.buf, 128, stdin);
msg_snd.buf[strlen(msg_snd.buf) - 1] = '\0';
msgsnd(msgid, &msg_snd, SIZE, 0);
if (strncmp(msg_snd.buf, "quit", 4) == 0) {
kill(pid, SIGKILL);
break;
}
}
}
return 0;
err:
msgctl(msgid, IPC_RMID, NULL);
}
c
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/types.h>
int main() {
key_t key;
if ((key = ftok(".", 'q')) < 0) {
perror("error");
return -1;
}
int shmid;
char* shm = "";
// 创建/打开共享内存
if ((shmid = shmget(key, 512, IPC_CREAT | IPC_EXCL | 0664)) < 0) {
if (errno != EEXIST) {
perror("err");
return -1;
} else {
shmid = shmget(key, 512, 0664);
}
}
if ((shm = shmat(shmid, NULL, 0)) > 0) {
printf("%p", shm);
}
int semid;
int semun;
// 创建/打开信号灯
struct sembuf sem;
semid = semget(key, 2, IPC_CREAT | IPC_EXCL | 0664);
if (semid < 0) {
if (errno != EEXIST) {
perror("error");
return -1;
} else {
semid = semget(key, 2, 0644);
}
} else {
semun = 0;
semctl(semid, 0, SETVAL, semun);
semun = 1;
semctl(semid, 1, SETVAL, semun);
}
// 读操作
while (1) {
sem.sem_num = 1;
sem.sem_op = -1;
sem.sem_flg = 0;
semop(semid, &sem, 1);
fgets(shm, 128, stdin);
shm[strlen(shm) - 1] = '\0';
sem.sem_num = 0;
sem.sem_op = 1;
sem.sem_flg = 0;
semop(semid, &sem, 1);
if (strncmp(shm, "quit", 4) == 0) {
goto ERR;
}
}
// 写操作
while (1) {
sem.sem_num = 0;
sem.sem_op = -1;
sem.sem_flg = 0;
semop(semid, &sem, 1);
if (strncmp(shm, "quit", 4) == 0) {
goto ERR;
}
printf("%s", shm);
sem.sem_num = 1;
sem.sem_op = 1;
sem.sem_flg = 0;
semop(semid, &sem, 1);
}
return 0;
ERR:
shmdt(shm);
shmctl(shmid, IPC_RMID, NULL);
semctl(semid, 0, IPC_RMID, NULL);
semctl(semid, 1, IPC_RMID, NULL);
}
网络
- 层级
- 网络接口和物理层(以太网)
- 网络层(IP)
- 传输层(TCP UDP)
- 应用层(Telnet FTP HTTP)
- IP
in_addr_t inet_aton(ipstr)
int inet_addr(ipstr, in_addr_t)
inet_pton(ipv6)
十转二char* inet_ntoa(in_addr_t)
inet_ntop(ipv6)
二转十
- 端口 2^16 0-65536 1-1023 系统 1024-49151 用户 49152-65536 私有
- 字节序 主机往往采用小端存储 网络字节序采用大端存储
- 套接字
- 类型
- 流式~ TCP
- 数据包~ UDP
- 原始~ IP 主要用于协议开发
- TCP
- 服务端 socket() bind() listen() accept() recv()/recvfrom() send/sendto() close()
- 客户端 socket()
[bind()]
connect() send()/sendto() recv()/recvfrom() close()
- UDP
- 服务端 socket() bind() recvfrom() sendfrom()
- 客户端 socket() sendto() recvfrom() close()
- 类型
- 数据包
- 三握四挥
- s socket() bind() listen()
- c connect() 发送syn
- s 发送ack syn
- c ack
- 通信
- c 调用close() 发送fin
- s 确认ack 然后close()发送fin
- c 确认ack
- 封装 解析
- 以太网头部 IP头部 TCP/UDP头部 数据 以太网尾部
- 封包格式 抓包 略
- 三握四挥
c
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <sys/types.h>
int main(int argc, char const* argv[]) {
int sockfd, acceptfd;
struct sockaddr_in serveraddr, clientaddr;
socklen_t addrlen = sizeof(serveraddr);
char buf[128] = {};
bzero(&serveraddr, addrlen);
bzero(&clearerr, addrlen);
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
goto err;
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
serveraddr.sin_port = htons(atoi(argv[2]));
if (bind(sockfd, (struct sockadd*)&serveraddr, addrlen) < 0)
goto err;
// udp不用listen和accept
if (listen(sockfd, 5) < 0) {
perror("error");
return;
}
// 阻塞等待连接
if ((acceptfd = accept(sockfd, &clientaddr, &addrlen)) < 0)
goto err;
printf("ip: %s,port: %d\n", inet_ntoa(clientaddr.sin_addr),
ntohs(clientaddr.sin_port));
int bytes;
while (1) {
if ((bytes = recv(acceptfd, buf, 128, 0)) < 0)
goto err;
else if (strncmp(buf, "quit", 4) == 0)
goto close;
else {
printf("client: %s\n", buf);
strcat(buf, "-server");
if (send(acceptfd, buf, 128, 0) < 0)
goto err;
}
}
return 0;
err:
perror("error");
return -1;
close:
close(acceptfd);
close(sockfd);
return 0;
}
c
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <sys/types.h>
int main(int argc, char const* argv[]) {
int sockfd;
struct sockaddr_in serveraddr;
socklen_t addrlen = sizeof(serveraddr);
char buf[128] = {};
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
goto err;
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
serveraddr.sin_port = htons(atoi(argv[2]));
// udp 不用connect
if (connect(sockfd, &serveraddr, addrlen) < 0)
goto err;
while (1) {
fgets(buf, 128, stdin);
buf[strlen(buf) - 1] = '\0';
if (send(sockfd, buf, 128, 0) < 0)
goto err;
if (strncmp(buf, "quit", 4) == 0)
goto close;
if (recv(sockfd, buf, 128, 0) < 0)
goto err;
printf("server: %s\n", buf);
}
return 0;
err:
perror("error");
return -1;
close:
close(sockfd);
return 0;
}
服务器
- I/O模型
- 阻塞
fgets()
recvfrom()
- 非阻塞
flags = fcntl(fd,F_GETFL)
flags = flags | O_NONBLOCK
fcntl(fd, F_SETFL, flags)
- IO多路复用
unistd.h
sys/select.h
- 在一个程序中处理多个I/O流, 如果阻塞就会影响运行,如果非阻塞就会轮询浪费资源
select(fds, read, write, except, timeout)
监听文件描述符状态变化FD_CLR() FD_ISSET() FD_SET() FD_ZERO()
删除 是否在 添加 清空- 信号驱动I/O略
poll() epoll()
- select 数量有限制 开销大 遍历 水平触发
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
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);
- poll 链表保存⽂件描述符 没有数量限制 其它同上
- epoll 使⽤⼀个⽂件描述符管理多个描述符 存放到内核的⼀个事件表 事件触发的,不是轮询查询的 效率高
- 阻塞
- 服务器模型
- 循环服务器 依次处理每个客户端 不能同时多个
while(1){accept();while(1){recv();send();break;}}
- 并发服务器
- select并发
- 文件服务器
- udp聊天室
- 循环服务器 依次处理每个客户端 不能同时多个
c
#include <netinet/in.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 8080
#define MAX_CLIENTS 5
void* handle_client(void* arg) {
int client_sock = *(int*)arg;
char buffer[1024];
while (1) {
memset(buffer, 0, sizeof(buffer));
int bytes_received = recv(client_sock, buffer, sizeof(buffer), 0);
if (bytes_received <= 0) {
break;
}
printf("Received from client: %s\n", buffer);
send(client_sock, buffer, bytes_received, 0);
}
close(client_sock);
return NULL;
}
int main() {
int server_sock = socket(AF_INET, SOCK_STREAM, 0);
if (server_sock == -1) {
perror("Failed to create socket");
exit(EXIT_FAILURE);
}
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) ==
-1) {
perror("Failed to bind socket");
exit(EXIT_FAILURE);
}
if (listen(server_sock, MAX_CLIENTS) == -1) {
perror("Failed to listen on socket");
exit(EXIT_FAILURE);
}
printf("Server listening on port %d...\n", PORT);
while (1) {
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
int client_sock =
accept(server_sock, (struct sockaddr*)&client_addr, &client_addr_len);
if (client_sock == -1) {
perror("Failed to accept client connection");
continue;
}
printf("Accepted connection from client\n");
pthread_t thread;
if (pthread_create(&thread, NULL, handle_client, (void*)&client_sock) !=
0) {
perror("Failed to create thread");
close(client_sock);
continue;
}
pthread_detach(thread);
}
close(server_sock);
return 0;
}
c
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#define PORT 8080
#define MAX_CLIENTS 5
void handle_client(int client_sock) {
char buffer[1024];
while (1) {
memset(buffer, 0, sizeof(buffer));
int bytes_received = recv(client_sock, buffer, sizeof(buffer), 0);
if (bytes_received <= 0) {
break;
}
printf("Received from client: %s\n", buffer);
send(client_sock, buffer, bytes_received, 0);
}
close(client_sock);
}
int main() {
int server_sock = socket(AF_INET, SOCK_STREAM, 0);
if (server_sock == -1) {
perror("Failed to create socket");
exit(EXIT_FAILURE);
}
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) ==
-1) {
perror("Failed to bind socket");
exit(EXIT_FAILURE);
}
if (listen(server_sock, MAX_CLIENTS) == -1) {
perror("Failed to listen on socket");
exit(EXIT_FAILURE);
}
printf("Server listening on port %d...\n", PORT);
while (1) {
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
int client_sock =
accept(server_sock, (struct sockaddr*)&client_addr, &client_addr_len);
if (client_sock == -1) {
perror("Failed to accept client connection");
continue;
}
printf("Accepted connection from client\n");
pid_t pid = fork();
if (pid == -1) {
perror("Failed to fork process");
close(client_sock);
continue;
} else if (pid > 0) {
// Parent process
close(client_sock);
wait(NULL); // Wait for child process to finish
} else {
// Child process
handle_client(client_sock);
exit(EXIT_SUCCESS);
}
}
close(server_sock);
return 0;
}
c
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 8080
#define MAX_CLIENTS 5
void handle_client(int client_sock) {
char buffer[1024];
while (1) {
memset(buffer, 0, sizeof(buffer));
int bytes_received = recv(client_sock, buffer, sizeof(buffer), 0);
if (bytes_received <= 0) {
break;
}
printf("Received from client: %s\n", buffer);
send(client_sock, buffer, bytes_received, 0);
}
close(client_sock);
}
int main() {
int server_sock = socket(AF_INET, SOCK_STREAM, 0);
if (server_sock == -1) {
perror("Failed to create socket");
exit(EXIT_FAILURE);
}
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) ==
-1) {
perror("Failed to bind socket");
exit(EXIT_FAILURE);
}
if (listen(server_sock, MAX_CLIENTS) == -1) {
perror("Failed to listen on socket");
exit(EXIT_FAILURE);
}
printf("Server listening on port %d...\n", PORT);
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(server_sock, &read_fds);
int max_fd = server_sock;
while (1) {
fd_set temp_fds = read_fds;
int activity = select(max_fd + 1, &temp_fds, NULL, NULL, NULL);
if (activity < 0) {
perror("Error occurred in select()");
exit(EXIT_FAILURE);
}
for (int i = 0; i <= max_fd && activity > 0; i++) {
if (FD_ISSET(i, &temp_fds)) {
if (i == server_sock) {
// New client connection
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
int client_sock = accept(server_sock, (struct sockaddr*)&client_addr,
&client_addr_len);
if (client_sock == -1) {
perror("Failed to accept client connection");
continue;
}
printf("Accepted connection from client\n");
FD_SET(client_sock, &read_fds);
if (client_sock > max_fd) {
max_fd = client_sock;
}
} else {
// Client message received
handle_client(i);
FD_CLR(i, &read_fds);
}
activity--;
}
}
}
close(server_sock);
return 0;
}
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/select.h>
#define BUF_SIZE 1024
#define PORT 12345
int main() {
int server_sock, client_sock;
struct sockaddr_in server_addr, client_addr;
socklen_t client_addr_size;
char buffer[BUF_SIZE];
fd_set read_fds, temp_fds;
int max_fd;
// 创建套接字
server_sock = socket(PF_INET, SOCK_STREAM, 0);
if (server_sock == -1) {
perror("socket");
exit(1);
}
// 配置服务器地址
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(PORT);
// 绑定套接字
if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("bind");
exit(1);
}
// 监听套接字
if (listen(server_sock, 5) == -1) {
perror("listen");
exit(1);
}
// 初始化文件描述符集合
FD_ZERO(&read_fds);
FD_SET(server_sock, &read_fds);
max_fd = server_sock;
while (1) {
temp_fds = read_fds;
// 使用select检查文件描述符集合中的套接字状态
if (select(max_fd + 1, &temp_fds, NULL, NULL, NULL) == -1) {
perror("select");
break;
}
// 遍历文件描述符集合,处理可读事件
for (int i = 0; i <= max_fd; i++) {
if (FD_ISSET(i, &temp_fds)) {
if (i == server_sock) { // 有新的连接请求
client_addr_size = sizeof(client_addr);
client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_addr_size);
if (client_sock == -1) {
perror("accept");
break;
}
printf("New client connected: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
FD_SET(client_sock, &read_fds);
if (client_sock > max_fd) {
max_fd = client_sock;
}
} else { // 有数据可读
int len = read(i, buffer, BUF_SIZE);
if (len <= 0) { // 客户端断开连接或出错
close(i);
FD_CLR(i, &read_fds);
} else { // 收到数据,发送回客户端
write(i, buffer, len);
}
}
}
}
}
close(server_sock);
return 0;
}
c
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 8080
#define MAX_CLIENTS 5
void handle_client(int client_sock) {
char buffer[1024];
while (1) {
memset(buffer, 0, sizeof(buffer));
int bytes_received = recv(client_sock, buffer, sizeof(buffer), 0);
if (bytes_received <= 0) {
break;
}
printf("Received from client: %s\n", buffer);
send(client_sock, buffer, bytes_received, 0);
}
close(client_sock);
}
int main() {
int server_sock = socket(AF_INET, SOCK_STREAM, 0);
if (server_sock == -1) {
perror("Failed to create socket");
exit(EXIT_FAILURE);
}
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) ==
-1) {
perror("Failed to bind socket");
exit(EXIT_FAILURE);
}
if (listen(server_sock, MAX_CLIENTS) == -1) {
perror("Failed to listen on socket");
exit(EXIT_FAILURE);
}
printf("Server listening on port %d...\n", PORT);
int epoll_fd = epoll_create1(0);
if (epoll_fd == -1) {
perror("Failed to create epoll file descriptor");
exit(EXIT_FAILURE);
}
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = server_sock;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_sock, &event) == -1) {
perror("Failed to add server socket to epoll");
exit(EXIT_FAILURE);
}
while (1) {
struct epoll_event events[MAX_CLIENTS];
int num_events = epoll_wait(epoll_fd, events, MAX_CLIENTS, -1);
if (num_events == -1) {
perror("Error occurred in epoll_wait()");
exit(EXIT_FAILURE);
}
for (int i = 0; i < num_events; i++) {
if (events[i].data.fd == server_sock) {
// New client connection
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
int client_sock = accept(server_sock, (struct sockaddr*)&client_addr,
&client_addr_len);
if (client_sock == -1) {
perror("Failed to accept client connection");
continue;
}
printf("Accepted connection from client\n");
event.events = EPOLLIN | EPOLLET;
event.data.fd = client_sock;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_sock, &event) == -1) {
perror("Failed to add client socket to epoll");
close(client_sock);
continue;
}
} else {
// Client message received
handle_client(events[i].data.fd);
if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL) == -1) {
perror("Failed to remove client socket from epoll");
}
close(events[i].data.fd);
}
}
}
close(server_sock);
return 0;
}
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/epoll.h>
#define MAX_EVENTS 10
#define BUF_SIZE 1024
void setnonblocking(int sockfd) {
int opts = fcntl(sockfd, F_GETFL);
if (opts < 0) {
perror("fcntl(F_GETFL)");
exit(EXIT_FAILURE);
}
opts = (opts | O_NONBLOCK);
if (fcntl(sockfd, F_SETFL, opts) < 0) {
perror("fcntl(F_SETFL)");
exit(EXIT_FAILURE);
}
}
int main(int argc, char *argv[]) {
int server_sockfd, client_sockfd;
struct sockaddr_in server_addr, client_addr;
socklen_t client_addr_len = sizeof(client_addr);
char buffer[BUF_SIZE];
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (server_sockfd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(8888);
if (bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
if (listen(server_sockfd, 5) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
int epoll_fd = epoll_create1(0);
if (epoll_fd == -1) {
perror("epoll_create1");
exit(EXIT_FAILURE);
}
struct epoll_event event, events[MAX_EVENTS];
event.events = EPOLLIN;
event.data.fd = server_sockfd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_sockfd, &event) == -1) {
perror("epoll_ctl: server_sockfd");
exit(EXIT_FAILURE);
}
while (1) {
int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
if (nfds == -1) {
perror("epoll_wait");
exit(EXIT_FAILURE);
}
for (int i = 0; i < nfds; ++i) {
if (events[i].data.fd == server_sockfd) {
client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_addr, &client_addr_len);
if (client_sockfd == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
setnonblocking(client_sockfd);
event.events = EPOLLIN | EPOLLET;
event.data.fd = client_sockfd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_sockfd, &event) == -1) {
perror("epoll_ctl: client_sockfd");
exit(EXIT_FAILURE);
}
} else {
int done = 0;
while (1) {
ssize_t count = read(events[i].data.fd, buffer, BUF_SIZE);
if (count == -1) {
if (errno != EAGAIN) {
perror("read");
done = 1;
}
break;
} else if (count == 0) {
done = 1;
break;
}
write(events[i].data.fd, buffer, count);
}
if (done) {
close(events[i].data.fd);
}
}
}
}
close(server_sockfd);
return 0;
}
c
#include <arpa/inet.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
void list(int acceptfd) {
DIR* dirp = opendir(".");
struct dirent* dirent;
char buf[128] = "";
while (dirent = readdir(dirp)) {
if (dirent->d_name[0] == '.')
continue;
else {
strcpy(buf, dirent->d_name);
send(acceptfd, buf, 128, 0);
}
}
send(acceptfd, "OVER", 128, 0);
return;
}
int download(int acceptfd, char* filename) {
char buf[128] = "";
int fd;
int bytes;
if ((fd = open(filename, O_RDONLY)) < 0) {
if (errno == ENOENT) {
strcpy(buf, "no exist");
send(acceptfd, buf, 128, 0);
return -1;
} else
perror("error");
}
strcpy(buf, "yes exist");
send(acceptfd, buf, 128, 0);
while ((bytes = read(fd, buf, 128)) > 0)
send(acceptfd, buf, bytes, 0);
sleep(1);
strcpy(buf, "OVER");
send(acceptfd, buf, 128, 0);
return 0;
}
void upload(int acceptfd, char* filename) {
int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0664);
char buf[128] = "";
int bytes;
while ((bytes = recv(acceptfd, buf, 128, 0)) > 0) {
if (strncmp(buf, "OVER", 8) == 0)
break;
write(fd, buf, bytes);
}
return;
}
int main() {
int sockfd, acceptfd;
struct sockaddr_in serveraddr, clientaddr;
socklen_t addrlen = sizeof(serveraddr);
char buf[128] = "";
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
goto err;
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(8080);
serveraddr.sin_addr.s_addr = INADDR_ANY;
if ((bind(sockfd, &serveraddr, addrlen)) < 0)
goto err;
if ((listen(sockfd, 5)) < 0)
goto err;
while (1) {
if ((acceptfd = accept(sockfd, &clientaddr, &addrlen)) < 0)
goto err;
int bytes;
while (1) {
if ((bytes = recv(acceptfd, buf, 128, 0)) < 0)
goto err;
else if (bytes) {
printf("%s", buf);
switch (buf[0]) {
case 'L':
list(acceptfd);
break;
case 'D':
download(acceptfd, buf + 2);
break;
case 'P':
upload(acceptfd, buf + 2);
break;
}
} else
break;
}
}
close(acceptfd);
close(sockfd);
return 0;
err:
perror("error");
return -1;
}
c
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
typedef struct {
int type;
char name[128];
char text[128];
} MSG;
typedef struct node {
struct sockaddr_in addr;
struct node* next;
} link_t;
link_t* link_create() {
link_t* h = (link_t*)malloc(sizeof(link_t));
h->next = NULL;
return h;
}
link_t* link_create();
void login(MSG msg, link_t* h, int sockfd, struct sockaddr_in clientaddr) {
link_t* p = h;
sprintf(msg.text, "---%s login---", msg.name);
// 遍历链表
while (p->next != NULL) {
sendto(sockfd, &msg, sizeof(msg), 0, &p->next->addr,
sizeof(struct sockaddr_in));
p = p->next;
}
link_t* temp = (link_t*)malloc(sizeof(link_t));
temp->addr = clientaddr;
temp->next = h->next;
h->next = temp;
return;
}
void chat(MSG msg, link_t* h, int sockfd, struct sockaddr_in clientaddr) {
char buf[128] = "";
link_t* p = h;
sprintf(buf, "%s : %s", msg.name, msg.text);
strcpy(msg.text, buf);
while (p->next) {
// 自己跳过
if (memcmp(&clientaddr, &p->next->addr, sizeof(clientaddr)) == 0)
p = p->next;
else {
sendto(sockfd, &msg, sizeof(msg), 0, &p->next->addr,
sizeof(struct sockaddr_in));
p = p->next;
}
}
return;
}
void quitt(MSG msg, link_t* h, int sockfd, struct sockaddr_in clientaddr) {
link_t* p = h;
link_t* temp;
sprintf(msg.text, "---%s offline ---", msg.name);
while (p->next) {
// 自己跳过
if (memcmp(&clientaddr, &p->next->addr, sizeof(clientaddr)) == 0) {
temp = p->next;
p->next = temp->next;
free(temp);
temp = NULL;
} else {
sendto(sockfd, &msg, sizeof(msg), 0, &p->next->addr,
sizeof(struct sockaddr_in));
p = p->next;
}
}
return;
}
int main() {
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in serveraddr, clientaddr;
socklen_t addrlen = sizeof(serveraddr);
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(8080);
serveraddr.sin_addr.s_addr = INADDR_ANY;
bind(sockfd, &serveraddr, addrlen);
MSG msg;
pid_t pid = fork();
if (pid) {
link_t* h = link_create();
while (1) {
recvfrom(sockfd, &msg, sizeof(msg), 0, &clientaddr, &addrlen);
switch (msg.type) {
case 1:
login(msg, h, sockfd, clientaddr);
break;
case 2:
chat(msg, h, sockfd, clientaddr);
break;
case 3:
quitt(msg, h, sockfd, clientaddr);
break;
}
}
} else {
// 子进程发送系统信息
msg.type = 2;
strcpy(msg.name, "server");
while (1) {
fgets(msg.text, 128, stdin);
msg.text[strlen(msg.text) - 1] = '\0';
sendto(sockfd, &msg, sizeof(msg), 0, &serveraddr, addrlen);
}
}
return 0;
}
网络进阶
- 超时检测
getsockopt()
setsockopt()
select()
- 定时器信号
- 广播
ifconfig
查看广播地址sockfd = socket(AF_INET, SOCK_DGRAM, 0)
sendto(sockfd,buf,128,0,&broadcastaddr,addrlen)
- 组播
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = 224-239
mreq.imr_interface.s_addr = htonl(INADDR_ANY)
setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq, sizeof(mreq))
- Unix域套接字
- 用于进程间通信
struct sockaddr_un
- tcp
- 服务端 创建 将sockfd和本地信息绑定 设置监听模式 接收连接请求 发送和接收
- 客户端 创建 指定服务端 建立连接 发送和接收
- udp
- 服务端 创建 填充本地信息结构体 绑定套接字 发送和接收
- 客户端 创建 填充双方本地信息 绑定 通信
- 用于进程间通信
- 原始套接字
- 用于读写ICMP IGMP等其他网络报文或自行构造ip头部和协议
- 链路层创建
sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
需管理员 - 网络层创建 通过
setsockopt()
设置IP_HDRINCL 使得能自行构造ip头部 - ICMP Ethernet 封包解析
- MAC接收和发送
- ARP实现MAC地址扫描 ARP是网络层和链路层之间的协议
- 创建原始套接字
- 组MAC头
- 组ARP头
- 将ARP请求通过eth0发送出去
- 用ioctl()获取本机网络地址并设置sockaddr_ll
- 接收数据
- 分析ARP数据包
c
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
int main() {
int sockfd, acceptfd;
struct sockaddr_un s_addr, c_addr;
socklen_t addrlen = sizeof(s_addr);
char buf[128] = "";
bzero(&s_addr, addrlen);
bzero(&c_addr, addrlen);
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
// sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
// 和socket的主要区别
s_addr.sun_family = AF_UNIX;
strcpy(s_addr.sun_path, "./stream");
bind(sockfd, &s_addr, addrlen);
// udp不用
listen(sockfd, 5);
acceptfd = accept(sockfd, &c_addr, &addrlen);
int r;
while (1) {
// udp用sockfd
r = recv(acceptfd, buf, 128, 0);
if (r) {
if (strncmp(buf, "quit", 4) == 0) {
printf("quit\n");
break;
} else {
printf("client: %s\n", buf);
strcat(buf, "--server");
send(acceptfd, buf, 128, 0);
}
} else {
printf("no data\n");
exit(1);
}
}
return 0;
}
应用
- sqlite
sqlite/sqlite3.h
sqlite3_open(filename,sqlite3)
创建sqlite3_errmsg(sqlite3)
输出报错sqlite3_close(sqlite3)
关闭sqlite3_exec(sqlite3, sql_cmd, callback, arg, errmsg)
执行sqlite3_get_table(sqlite3, sql_cmd, result, rows, columns,errmsg)
查询数据库sqlite3_free_table(result)
释放查询结果
- 管理系统