wordpress 站外调用,网站后台开发费用,网易企业邮箱入口登录,陕西省建设监理协会官方网站文章目录#xff1a;
一#xff1a;线程池模块分析
threadpool.c
二#xff1a;UDP通信
1.TCP通信和UDP通信各自的优缺点
2.UDP实现的C/S模型
server.c
client.c
三#xff1a;套接字
1.本地套接字
2.本地套 和 网络套对比
server.c
client.c 一#xff1a;线…文章目录
一线程池模块分析
threadpool.c
二UDP通信
1.TCP通信和UDP通信各自的优缺点
2.UDP实现的C/S模型
server.c
client.c
三套接字
1.本地套接字
2.本地套 和 网络套对比
server.c
client.c 一线程池模块分析 struct threadpool_t {pthread_mutex_t lock; /* 用于锁住本结构体 */ pthread_mutex_t thread_counter; /* 记录忙状态线程个数de琐 -- busy_thr_num */pthread_cond_t queue_not_full; /* 当任务队列满时添加任务的线程阻塞等待此条件变量 */pthread_cond_t queue_not_empty; /* 任务队列里不为空时通知等待任务的线程 */pthread_t *threads; /* 存放线程池中每个线程的tid。数组 */pthread_t adjust_tid; /* 存管理线程tid */threadpool_task_t *task_queue; /* 任务队列(数组首地址) */int min_thr_num; /* 线程池最小线程数 */int max_thr_num; /* 线程池最大线程数 */int live_thr_num; /* 当前存活线程个数 */int busy_thr_num; /* 忙状态线程个数 */int wait_exit_thr_num; /* 要销毁的线程个数 */int queue_front; /* task_queue队头下标 */int queue_rear; /* task_queue队尾下标 */int queue_size; /* task_queue队中实际任务数 */int queue_max_size; /* task_queue队列可容纳任务数上限 */int shutdown; /* 标志位线程池使用状态true或false */
};typedef struct {void *(*function)(void *); /* 函数指针回调函数 */void *arg; /* 上面函数的参数 */} threadpool_task_t; /* 各子线程任务结构体 */rear 5 % 5 线程池模块分析1. main(); 创建线程池。向线程池中添加任务。 借助回调处理任务。销毁线程池。2. pthreadpool_create();创建线程池结构体 指针。初始化线程池结构体 { N 个成员变量 }创建 N 个任务线程。创建 1 个管理者线程。失败时销毁开辟的所有空间。释放3. threadpool_thread进入子线程回调函数。接收参数 void *arg --》 pool 结构体加锁 --》lock --》 整个结构体锁判断条件变量 --》 wait -------------------1704. adjust_thread循环 10 s 执行一次。进入管理者线程回调函数接收参数 void *arg --》 pool 结构体加锁 --》lock --》 整个结构体锁获取管理线程池要用的到 变量。 task_num, live_num, busy_num根据既定算法使用上述3变量判断是否应该 创建、销毁线程池中 指定步长的线程。5. threadpool_add ()总功能模拟产生任务。 num[20]设置回调函数 处理任务。 sleep1 代表处理完成。内部实现加锁初始化 任务队列结构体成员。 回调函数 function arg利用环形队列机制实现添加任务。 借助队尾指针挪移 % 实现。唤醒阻塞在 条件变量上的线程。解锁6. 从 3. 中的wait之后继续执行处理任务。加锁获取 任务处理回调函数及参数利用环形队列机制实现处理任务。 借助队头指针挪移 % 实现。唤醒阻塞在 条件变量 上的 server。解锁加锁 改忙线程数解锁执行处理任务的线程加锁 改忙线程数——解锁7. 创建 销毁线程管理者线程根据 task_num, live_num, busy_num 根据既定算法使用上述3变量判断是否应该 创建、销毁线程池中 指定步长的线程。如果满足 创建条件pthread_create(); 回调 任务线程函数。 live_num如果满足 销毁条件wait_exit_thr_num 10; signal 给 阻塞在条件变量上的线程 发送 假条件满足信号 跳转至 --170 wait阻塞线程会被 假信号 唤醒。判断 wait_exit_thr_num 0 pthread_exit(); threadpool.c #include stdlib.h
#include pthread.h
#include unistd.h
#include assert.h
#include stdio.h
#include string.h
#include signal.h
#include errno.h
#include threadpool.h#define DEFAULT_TIME 10 /*10s检测一次*/
#define MIN_WAIT_TASK_NUM 10 /*如果queue_size MIN_WAIT_TASK_NUM 添加新的线程到线程池*/
#define DEFAULT_THREAD_VARY 10 /*每次创建和销毁线程的个数*/
#define true 1
#define false 0typedef struct {void *(*function)(void *); /* 函数指针回调函数 */void *arg; /* 上面函数的参数 */
} threadpool_task_t; /* 各子线程任务结构体 *//* 描述线程池相关信息 */struct threadpool_t {pthread_mutex_t lock; /* 用于锁住本结构体 */ pthread_mutex_t thread_counter; /* 记录忙状态线程个数de琐 -- busy_thr_num */pthread_cond_t queue_not_full; /* 当任务队列满时添加任务的线程阻塞等待此条件变量 */pthread_cond_t queue_not_empty; /* 任务队列里不为空时通知等待任务的线程 */pthread_t *threads; /* 存放线程池中每个线程的tid。数组 */pthread_t adjust_tid; /* 存管理线程tid */threadpool_task_t *task_queue; /* 任务队列(数组首地址) */int min_thr_num; /* 线程池最小线程数 */int max_thr_num; /* 线程池最大线程数 */int live_thr_num; /* 当前存活线程个数 */int busy_thr_num; /* 忙状态线程个数 */int wait_exit_thr_num; /* 要销毁的线程个数 */int queue_front; /* task_queue队头下标 */int queue_rear; /* task_queue队尾下标 */int queue_size; /* task_queue队中实际任务数 */int queue_max_size; /* task_queue队列可容纳任务数上限 */int shutdown; /* 标志位线程池使用状态true或false */
};void *threadpool_thread(void *threadpool);void *adjust_thread(void *threadpool);int is_thread_alive(pthread_t tid);
int threadpool_free(threadpool_t *pool);//threadpool_create(3,100,100);
threadpool_t *threadpool_create(int min_thr_num, int max_thr_num, int queue_max_size)
{int i;threadpool_t *pool NULL; /* 线程池 结构体 */do {if((pool (threadpool_t *)malloc(sizeof(threadpool_t))) NULL) { printf(malloc threadpool fail);break; /*跳出do while*/}pool-min_thr_num min_thr_num;pool-max_thr_num max_thr_num;pool-busy_thr_num 0;pool-live_thr_num min_thr_num; /* 活着的线程数 初值最小线程数 */pool-wait_exit_thr_num 0;pool-queue_size 0; /* 有0个产品 */pool-queue_max_size queue_max_size; /* 最大任务队列数 */pool-queue_front 0;pool-queue_rear 0;pool-shutdown false; /* 不关闭线程池 *//* 根据最大线程上限数 给工作线程数组开辟空间, 并清零 */pool-threads (pthread_t *)malloc(sizeof(pthread_t)*max_thr_num); if (pool-threads NULL) {printf(malloc threads fail);break;}memset(pool-threads, 0, sizeof(pthread_t)*max_thr_num);/* 给 任务队列 开辟空间 */pool-task_queue (threadpool_task_t *)malloc(sizeof(threadpool_task_t)*queue_max_size);if (pool-task_queue NULL) {printf(malloc task_queue fail);break;}/* 初始化互斥琐、条件变量 */if (pthread_mutex_init((pool-lock), NULL) ! 0|| pthread_mutex_init((pool-thread_counter), NULL) ! 0|| pthread_cond_init((pool-queue_not_empty), NULL) ! 0|| pthread_cond_init((pool-queue_not_full), NULL) ! 0){printf(init the lock or cond fail);break;}/* 启动 min_thr_num 个 work thread */for (i 0; i min_thr_num; i) {pthread_create((pool-threads[i]), NULL, threadpool_thread, (void *)pool); /*pool指向当前线程池*/printf(start thread 0x%x...\n, (unsigned int)pool-threads[i]);}pthread_create((pool-adjust_tid), NULL, adjust_thread, (void *)pool); /* 创建管理者线程 */return pool;} while (0);threadpool_free(pool); /* 前面代码调用失败时释放poll存储空间 */return NULL;
}/* 向线程池中 添加一个任务 */
//threadpool_add(thp, process, (void*)num[i]); /* 向线程池中添加任务 process: 小写----大写*/int threadpool_add(threadpool_t *pool, void*(*function)(void *arg), void *arg)
{pthread_mutex_lock((pool-lock));/* 为真队列已经满 调wait阻塞 */while ((pool-queue_size pool-queue_max_size) (!pool-shutdown)) {pthread_cond_wait((pool-queue_not_full), (pool-lock));}if (pool-shutdown) {pthread_cond_broadcast((pool-queue_not_empty));pthread_mutex_unlock((pool-lock));return 0;}/* 清空 工作线程 调用的回调函数 的参数arg */if (pool-task_queue[pool-queue_rear].arg ! NULL) {pool-task_queue[pool-queue_rear].arg NULL;}/*添加任务到任务队列里*/pool-task_queue[pool-queue_rear].function function;pool-task_queue[pool-queue_rear].arg arg;pool-queue_rear (pool-queue_rear 1) % pool-queue_max_size; /* 队尾指针移动, 模拟环形 */pool-queue_size;/*添加完任务后队列不为空唤醒线程池中 等待处理任务的线程*/pthread_cond_signal((pool-queue_not_empty));pthread_mutex_unlock((pool-lock));return 0;
}/* 线程池中各个工作线程 */
void *threadpool_thread(void *threadpool)
{threadpool_t *pool (threadpool_t *)threadpool;threadpool_task_t task;while (true) {/* Lock must be taken to wait on conditional variable *//*刚创建出线程等待任务队列里有任务否则阻塞等待任务队列里有任务后再唤醒接收任务*/pthread_mutex_lock((pool-lock));/*queue_size 0 说明没有任务调 wait 阻塞在条件变量上, 若有任务跳过该while*/while ((pool-queue_size 0) (!pool-shutdown)) { printf(thread 0x%x is waiting\n, (unsigned int)pthread_self());pthread_cond_wait((pool-queue_not_empty), (pool-lock));/*清除指定数目的空闲线程如果要结束的线程个数大于0结束线程*/if (pool-wait_exit_thr_num 0) {pool-wait_exit_thr_num--;/*如果线程池里线程个数大于最小值时可以结束当前线程*/if (pool-live_thr_num pool-min_thr_num) {printf(thread 0x%x is exiting\n, (unsigned int)pthread_self());pool-live_thr_num--;pthread_mutex_unlock((pool-lock));pthread_exit(NULL);}}}/*如果指定了true要关闭线程池里的每个线程自行退出处理---销毁线程池*/if (pool-shutdown) {pthread_mutex_unlock((pool-lock));printf(thread 0x%x is exiting\n, (unsigned int)pthread_self());pthread_detach(pthread_self());pthread_exit(NULL); /* 线程自行结束 */}/*从任务队列里获取任务, 是一个出队操作*/task.function pool-task_queue[pool-queue_front].function;task.arg pool-task_queue[pool-queue_front].arg;pool-queue_front (pool-queue_front 1) % pool-queue_max_size; /* 出队模拟环形队列 */pool-queue_size--;/*通知可以有新的任务添加进来*/pthread_cond_broadcast((pool-queue_not_full));/*任务取出后立即将 线程池琐 释放*/pthread_mutex_unlock((pool-lock));/*执行任务*/ printf(thread 0x%x start working\n, (unsigned int)pthread_self());pthread_mutex_lock((pool-thread_counter)); /*忙状态线程数变量琐*/pool-busy_thr_num; /*忙状态线程数1*/pthread_mutex_unlock((pool-thread_counter));(*(task.function))(task.arg); /*执行回调函数任务*///task.function(task.arg); /*执行回调函数任务*//*任务结束处理*/ printf(thread 0x%x end working\n, (unsigned int)pthread_self());pthread_mutex_lock((pool-thread_counter));pool-busy_thr_num--; /*处理掉一个任务忙状态数线程数-1*/pthread_mutex_unlock((pool-thread_counter));}pthread_exit(NULL);
}/* 管理线程 */
void *adjust_thread(void *threadpool)
{int i;threadpool_t *pool (threadpool_t *)threadpool;while (!pool-shutdown) {sleep(DEFAULT_TIME); /*定时 对线程池管理*/pthread_mutex_lock((pool-lock));int queue_size pool-queue_size; /* 关注 任务数 */int live_thr_num pool-live_thr_num; /* 存活 线程数 */pthread_mutex_unlock((pool-lock));pthread_mutex_lock((pool-thread_counter));int busy_thr_num pool-busy_thr_num; /* 忙着的线程数 */pthread_mutex_unlock((pool-thread_counter));/* 创建新线程 算法 任务数大于最小线程池个数, 且存活的线程数少于最大线程个数时 如3010 40100*/if (queue_size MIN_WAIT_TASK_NUM live_thr_num pool-max_thr_num) {pthread_mutex_lock((pool-lock)); int add 0;/*一次增加 DEFAULT_THREAD 个线程*/for (i 0; i pool-max_thr_num add DEFAULT_THREAD_VARY pool-live_thr_num pool-max_thr_num; i) {if (pool-threads[i] 0 || !is_thread_alive(pool-threads[i])) {pthread_create((pool-threads[i]), NULL, threadpool_thread, (void *)pool);add;pool-live_thr_num;}}pthread_mutex_unlock((pool-lock));}/* 销毁多余的空闲线程 算法忙线程X2 小于 存活的线程数 且 存活的线程数 大于 最小线程数时*/if ((busy_thr_num * 2) live_thr_num live_thr_num pool-min_thr_num) {/* 一次销毁DEFAULT_THREAD个线程, 隨機10個即可 */pthread_mutex_lock((pool-lock));pool-wait_exit_thr_num DEFAULT_THREAD_VARY; /* 要销毁的线程数 设置为10 */pthread_mutex_unlock((pool-lock));for (i 0; i DEFAULT_THREAD_VARY; i) {/* 通知处在空闲状态的线程, 他们会自行终止*/pthread_cond_signal((pool-queue_not_empty));}}}return NULL;
}int threadpool_destroy(threadpool_t *pool)
{int i;if (pool NULL) {return -1;}pool-shutdown true;/*先销毁管理线程*/pthread_join(pool-adjust_tid, NULL);for (i 0; i pool-live_thr_num; i) {/*通知所有的空闲线程*/pthread_cond_broadcast((pool-queue_not_empty));}for (i 0; i pool-live_thr_num; i) {pthread_join(pool-threads[i], NULL);}threadpool_free(pool);return 0;
}int threadpool_free(threadpool_t *pool)
{if (pool NULL) {return -1;}if (pool-task_queue) {free(pool-task_queue);}if (pool-threads) {free(pool-threads);pthread_mutex_lock((pool-lock));pthread_mutex_destroy((pool-lock));pthread_mutex_lock((pool-thread_counter));pthread_mutex_destroy((pool-thread_counter));pthread_cond_destroy((pool-queue_not_empty));pthread_cond_destroy((pool-queue_not_full));}free(pool);pool NULL;return 0;
}int threadpool_all_threadnum(threadpool_t *pool)
{int all_threadnum -1; // 总线程数pthread_mutex_lock((pool-lock));all_threadnum pool-live_thr_num; // 存活线程数pthread_mutex_unlock((pool-lock));return all_threadnum;
}int threadpool_busy_threadnum(threadpool_t *pool)
{int busy_threadnum -1; // 忙线程数pthread_mutex_lock((pool-thread_counter));busy_threadnum pool-busy_thr_num; pthread_mutex_unlock((pool-thread_counter));return busy_threadnum;
}int is_thread_alive(pthread_t tid)
{int kill_rc pthread_kill(tid, 0); //发0号信号测试线程是否存活if (kill_rc ESRCH) {return false;}return true;
}/*测试*/ #if 1/* 线程池中的线程模拟处理业务 */
void *process(void *arg)
{printf(thread 0x%x working on task %d\n ,(unsigned int)pthread_self(),(int)arg);sleep(1); //模拟 小---大写printf(task %d is end\n,(int)arg);return NULL;
}int main(void)
{/*threadpool_t *threadpool_create(int min_thr_num, int max_thr_num, int queue_max_size);*/threadpool_t *thp threadpool_create(3,100,100); /*创建线程池池里最小3个线程最大100队列最大100*/printf(pool inited);//int *num (int *)malloc(sizeof(int)*20);int num[20], i;for (i 0; i 20; i) {num[i] i;printf(add task %d\n,i);/*int threadpool_add(threadpool_t *pool, void*(*function)(void *arg), void *arg) */threadpool_add(thp, process, (void*)num[i]); /* 向线程池中添加任务 */}sleep(10); /* 等子线程完成任务 */threadpool_destroy(thp);return 0;
}#endif二UDP通信
1.TCP通信和UDP通信各自的优缺点 TCP通信和UDP通信各自的优缺点TCP 面向连接的可靠数据包传输。对于不稳定的网络层采取完全弥补的通信方式。 丢包重传优点稳定 数据流量稳定、速度稳定、顺序缺点传输速度慢。相率低。开销大使用场景数据的完整型要求较高不追求效率大数据传输、文件传输UDP 无连接的不可靠的数据报传递。对于不稳定的网络层采取完全不弥补的通信方式。 默认还原网络状况优点传输速度块。相率高。开销小缺点不稳定。数据流量。速度。顺序使用场景对时效性要求较高场合。稳定性其次游戏、视频会议、视频电话。 腾讯、华为、阿里 --- 应用层数据校验协议弥补udp的不足 2.UDP实现的C/S模型 UDP实现的 C/S 模型recv()/send() 只能用于 TCP 通信。 替代 read、writeaccpet(); ---- Connect(); ---被舍弃serverlfd socket(AF_INET, STREAM, 0); SOCK_DGRAM --- 报式协议bind();listen(); --- 可有可无while1{read(cfd, buf, sizeof) --- 被替换 --- recvfrom --- 涵盖accept传出地址结构ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);sockfd 套接字buf缓冲区地址len缓冲区大小flags 0src_addrstruct sockaddr *addr 传出。 对端地址结构addrlen传入传出。返回值 成功接收数据字节数。 失败-1 errn。 0 对端关闭。小-- 大write();--- 被替换 --- sendto---- connectssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);sockfd 套接字buf存储数据的缓冲区len数据长度flags 0src_addrstruct sockaddr *addr 传入。 目标地址结构addrlen地址结构长度返回值成功写出数据字节数。 失败 -1 errno }close();clientconnfd socket(AF_INET, SOCK_DGRAM, 0);sendto‘服务器的地址结构’ 地址结构大小recvfrom写到屏幕close();server.c #include string.h
#include stdio.h
#include unistd.h
#include arpa/inet.h
#include ctype.h#define SERV_PORT 8000int main(void)
{struct sockaddr_in serv_addr, clie_addr;socklen_t clie_addr_len;int sockfd;char buf[BUFSIZ];char str[INET_ADDRSTRLEN];int i, n;sockfd socket(AF_INET, SOCK_DGRAM, 0);bzero(serv_addr, sizeof(serv_addr));serv_addr.sin_family AF_INET;serv_addr.sin_addr.s_addr htonl(INADDR_ANY);serv_addr.sin_port htons(SERV_PORT);bind(sockfd, (struct sockaddr *)serv_addr, sizeof(serv_addr));printf(Accepting connections ...\n);while (1) {clie_addr_len sizeof(clie_addr);n recvfrom(sockfd, buf, BUFSIZ,0, (struct sockaddr *)clie_addr, clie_addr_len);if (n -1)perror(recvfrom error);printf(received from %s at PORT %d\n,inet_ntop(AF_INET, clie_addr.sin_addr, str, sizeof(str)),ntohs(clie_addr.sin_port));for (i 0; i n; i)buf[i] toupper(buf[i]);n sendto(sockfd, buf, n, 0, (struct sockaddr *)clie_addr, sizeof(clie_addr));if (n -1)perror(sendto error);}close(sockfd);return 0;
} client.c #include stdio.h
#include string.h
#include unistd.h
#include arpa/inet.h
#include ctype.h#define SERV_PORT 8000int main(int argc, char *argv[])
{struct sockaddr_in servaddr;int sockfd, n;char buf[BUFSIZ];sockfd socket(AF_INET, SOCK_DGRAM, 0);bzero(servaddr, sizeof(servaddr));servaddr.sin_family AF_INET;inet_pton(AF_INET, 127.0.0.1, servaddr.sin_addr);servaddr.sin_port htons(SERV_PORT);//bind(sockfd, (struct sockaddr *)servaddr, sizeof(servaddr)); //无效while (fgets(buf, BUFSIZ, stdin) ! NULL) {n sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)servaddr, sizeof(servaddr));if (n -1)perror(sendto error);n recvfrom(sockfd, buf, BUFSIZ, 0, NULL, 0); //NULL:不关心对端信息if (n -1)perror(recvfrom error);write(STDOUT_FILENO, buf, n);}close(sockfd);return 0;
} 三套接字
1.本地套接字 本地套接字IPC pipe、fifo、mmap、信号、本地套domain--- CS模型对比网络编程 TCP C/S模型 注意以下几点1. int socket(int domain, int type, int protocol); domainAF_INET -- AF_UNIX/AF_LOCAL type: SOCK_STREAM/SOCK_DGRAM 都可以2. 地址结构 sockaddr_in -- sockaddr_unstruct sockaddr_in srv_addr; -- struct sockaddr_un srv_adrr;srv_addr.sin_family AF_INET; -- srv_addr.sun_family AF_UNIX;srv_addr.sin_port htons(8888); strcpy(srv_addr.sun_path, srv.socket)srv_addr.sin_addr.s_addr htonl(INADDR_ANY); len offsetof(struct sockaddr_un, sun_path) strlen(srv.socket);bind(fd, (struct sockaddr *)srv_addr, sizeof(srv_addr)); -- bind(fd, (struct sockaddr *)srv_addr, len); 3. bind()函数调用成功会创建一个 socket。因此为保证bind成功通常我们在 bind之前使用 unlink(srv.socket);4. 客户端不能依赖 “隐式绑定”。并且应该在通信建立过程中创建且初始化2个地址结构client_addr -- bind()server_addr -- connect() 2.本地套 和 网络套对比 网络套接字 本地套接字serverlfd socket(AF_INET, SOCK_STREAM, 0); lfd socket(AF_UNIX, SOCK_STREAM, 0);bzero() ---- struct sockaddr_in serv_addr; bzero() ---- struct sockaddr_un serv_addr, clie_addr;serv_addr.sin_family AF_INET; serv_addr.sun_family AF_UNIX; serv_addr.sin_addr.s_addr htonl(INADDR_ANY); strcpyserv_addr.sun_path, 套接字文件名serv_addr.sin_port htons(8888); len offsetof(sockaddr_un, sun_path) strlen();unlink(套接字文件名); bind(lfd, (struct sockaddr *)serv_addr, sizeof()); bind(lfd, (struct sockaddr *)serv_addr, len); 创建新文件Listen(lfd, 128); Listen(lfd, 128);cfd Accept(lfd, ()clie_addr, len); cfd Accept(lfd, ()clie_addr, len); client lfd socket(AF_INET, SOCK_STREAM, 0); lfd socket(AF_UNIX, SOCK_STREAM, 0);隐式绑定 IPport bzero() ---- struct sockaddr_un clie_addr;clie_addr.sun_family AF_UNIX;strcpyclie_addr.sun_path, client套接字文件名len offsetof(sockaddr_un, sun_path) strlen();unlink( client套接字文件名);bind(lfd, (struct sockaddr *)clie_addr, len);bzero() ---- struct sockaddr_in serv_addr; bzero() ---- struct sockaddr_un serv_addr;serv_addr.sin_family AF_INET; serv_addr.sun_family AF_UNIX;inet_pton(AF_INT, 服务器IP, sin_addr.s_addr) strcpyserv_addr.sun_path, server套接字文件名 serv_addr.sin_port htons(服务器端口); len offsetof(sockaddr_un, sun_path) strlen(); connect(lfd, serv_addr, sizeof()); connect(lfd, serv_addr, len); server.c #include stdio.h
#include unistd.h
#include sys/socket.h
#include strings.h
#include string.h
#include ctype.h
#include arpa/inet.h
#include sys/un.h
#include stddef.h#include wrap.h#define SERV_ADDR serv.socketint main(void)
{int lfd, cfd, len, size, i;struct sockaddr_un servaddr, cliaddr;char buf[4096];lfd Socket(AF_UNIX, SOCK_STREAM, 0);bzero(servaddr, sizeof(servaddr));servaddr.sun_family AF_UNIX;strcpy(servaddr.sun_path, SERV_ADDR);len offsetof(struct sockaddr_un, sun_path) strlen(servaddr.sun_path); /* servaddr total len */unlink(SERV_ADDR); /* 确保bind之前serv.sock文件不存在,bind会创建该文件 */Bind(lfd, (struct sockaddr *)servaddr, len); /* 参3不能是sizeof(servaddr) */Listen(lfd, 20);printf(Accept ...\n);while (1) {len sizeof(cliaddr); //AF_UNIX大小108Bcfd Accept(lfd, (struct sockaddr *)cliaddr, (socklen_t *)len);len - offsetof(struct sockaddr_un, sun_path); /* 得到文件名的长度 */cliaddr.sun_path[len] \0; /* 确保打印时,没有乱码出现 */printf(client bind filename %s\n, cliaddr.sun_path);while ((size read(cfd, buf, sizeof(buf))) 0) {for (i 0; i size; i)buf[i] toupper(buf[i]);write(cfd, buf, size);}close(cfd);}close(lfd);return 0;
}client.c #include stdio.h
#include unistd.h
#include sys/types.h
#include sys/socket.h
#include strings.h
#include string.h
#include ctype.h
#include arpa/inet.h
#include sys/un.h
#include stddef.h#include wrap.h#define SERV_ADDR serv.socket
#define CLIE_ADDR clie.socketint main(void)
{int cfd, len;struct sockaddr_un servaddr, cliaddr;char buf[4096];cfd Socket(AF_UNIX, SOCK_STREAM, 0);bzero(cliaddr, sizeof(cliaddr));cliaddr.sun_family AF_UNIX;strcpy(cliaddr.sun_path,CLIE_ADDR);len offsetof(struct sockaddr_un, sun_path) strlen(cliaddr.sun_path); /* 计算客户端地址结构有效长度 */unlink(CLIE_ADDR);Bind(cfd, (struct sockaddr *)cliaddr, len); /* 客户端也需要bind, 不能依赖自动绑定*/bzero(servaddr, sizeof(servaddr)); /* 构造server 地址 */servaddr.sun_family AF_UNIX;strcpy(servaddr.sun_path, SERV_ADDR);len offsetof(struct sockaddr_un, sun_path) strlen(servaddr.sun_path); /* 计算服务器端地址结构有效长度 */Connect(cfd, (struct sockaddr *)servaddr, len);while (fgets(buf, sizeof(buf), stdin) ! NULL) {write(cfd, buf, strlen(buf));len read(cfd, buf, sizeof(buf));write(STDOUT_FILENO, buf, len);}close(cfd);return 0;
}