typedef 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 */
};
TCP | UDP | |
---|---|---|
特性 | 面向连接的,可靠的数据包传递。 对于不稳定的网络层。采取完全弥补的通信方式。 丢包重传。 |
无连接的,不可靠的数据报传递。 对于不稳定的网络层。采取完全不弥补的通信方式。 默认还原网络真实状态。 |
优点 | 数据流量稳定。速度稳定。顺序稳定。 | 传输速度快,相对高。开销小。 |
缺点 | 传输速度慢。通信效率低。开销大。 | 数据流量不稳定。速度不稳定。顺序不稳定。 |
使用场景 | 对数据完整性,要求较高, 不追求效率。—— 大数据传输。文件传参…… | 对数据时效性要求较高,稳定性其次。—— 视频会议、视频电话、游戏…… |
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
sockfd: 套接字
buf:缓冲区地址
len:缓冲区大小
flags:0
src_addr:(struct sockaddr *)&src_addr 传出对端的地址结构。——对应accpet理解。
addrlen:传入传出。——对应accpet理解。
返回:
成功:> 0 接收数据字节数。
0:对端关闭。
失败:-1, errno
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
sockfd: 套接字
buf:存储着数据的缓冲区地址
len:数据长度
flags:0
dest_addr:(struct sockaddr *)&src_addr 传入对端地址结构。——对应connect理解。
addrlen:地址结构长度。——对应accpet理解。
返回:
成功:实际写出的字节数。
失败:-1, errno
#include
#include
#include
#include
#include
#include
#include
#define SRV_PORT 8066
int main()
{
char buf[BUFSIZ] = {0};
char cltip[16] = {0};
struct sockaddr_in clt_addr,srv_addr;
socklen_t clt_addr_len;
bzero(&srv_addr,sizeof(srv_addr));
srv_addr.sin_family = AF_INET;
srv_addr.sin_port = htons(SRV_PORT);
srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd == -1)
{
perror("socket error");
exit(1);
}
int ret = bind(sockfd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));
if(-1 == ret)
{
perror("bind error");
exit(1);
}
while(1)
{
clt_addr_len = sizeof(clt_addr);
ret = recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&clt_addr,&clt_addr_len);
if(-1 == ret)
{
perror("recvfrom error");
exit(1);
}
printf("client ip:%s,port:%d\n",inet_ntop(AF_INET,&clt_addr.sin_addr.s_addr,cltip,sizeof(cltip)),ntohs(clt_addr.sin_port));
for(int i=0 ;i<ret ;++i)
{
buf[i] = toupper(buf[i]);
}
write(STDOUT_FILENO,buf,ret);
printf("\n");
ret = sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&clt_addr,clt_addr_len);
if(-1 == ret)
{
perror("sendto error");
exit(0);
}
}
close(sockfd);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#define SRV_PORT 8066
int main()
{
char buf[BUFSIZ] = {0};
struct sockaddr_in srv_addr;
socklen_t srv_addr_len = sizeof(srv_addr);
bzero(&srv_addr,sizeof(srv_addr));
srv_addr.sin_family = AF_INET;
srv_addr.sin_port = htons(SRV_PORT);
srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd == -1)
{
perror("socket error");
exit(1);
}
int ret,i = 0;
while(1)
{
char str[32] = {0};
sprintf(str,"%s %d","hello udp",i++);
printf("%s\n",str);
ret = sendto(sockfd,str,strlen(str),0,(struct sockaddr*)&srv_addr,srv_addr_len);
if(-1 == ret)
{
perror("sendto error");
exit(0);
}
ret = recvfrom(sockfd,buf,sizeof(buf),0,NULL,NULL);
if(-1 == ret)
{
perror("recvfrom error");
exit(1);
}
sleep(1);
}
close(sockfd);
return 0;
}
注意:可以通过 nc
命令充当UDP的客户端时,要加上 -u 选项