Linux Socket编程 -- 同步 与 异步 请求

什么是 异步 请求

   发起请求和 不需要等待 请求返回结果,直接去发起其他请求。

以DNS 请求为例 进行解析

       向 DNS 服务器发起请求,解析并打印返回结果。
       DNS 接口说明:
          struct dns_header header 结构体并通过函数 dns_create_header(&header) 获得 header
          struct dns_question question 结构体并通过函数 dns_create_question(&question,domain) 获得 question

然后传参 dns_build_request(&headr,&question,request) 获得 request
通过 snedto 发送 request 并获得 response
recvfrom(sockfd,buffer,sizeof(buffer),0,(struct sockaddr*)&addr, (socklen_t*)&addr_len);
dns_parse_response(buffer,&domains); //解析结果

例子: 同步DNS请求

char *domain[] = {
//	"www.ntytcp.com",
//	"bojing.wang",
	"www.baidu.com",
	"tieba.baidu.com",
	"news.baidu.com",
	"zhidao.baidu.com",
	"music.baidu.com",
	"image.baidu.com",
	"v.baidu.com",
	"map.baidu.com",
	"baijiahao.baidu.com",
	"xueshu.baidu.com",
	"cloud.baidu.com",
	"www.163.com",
	"open.163.com",
	"auto.163.com",
	"gov.163.com",
	"money.163.com",
	"sports.163.com",
	"tech.163.com",
	"edu.163.com",
	"www.taobao.com",
	"q.taobao.com",
	"sf.taobao.com",
	"yun.taobao.com",
	"baoxian.taobao.com",
	"www.tmall.com",
	"suning.tmall.com",
	"www.tencent.com",
	"www.qq.com",
	"www.aliyun.com",
	"www.ctrip.com",
	"hotels.ctrip.com",
	"hotels.ctrip.com",
	"vacations.ctrip.com",
	"flights.ctrip.com",
	"trains.ctrip.com",
	"bus.ctrip.com",
	"car.ctrip.com",
	"piao.ctrip.com",
	"tuan.ctrip.com",
	"you.ctrip.com",
	"g.ctrip.com",
	"lipin.ctrip.com",
	"ct.ctrip.com"
};

void dns_client_commit(const char *domain )
{
	// 创建 socket 
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd < 0){
        perror("create socket failed\n");
        exit(-1);
    }
    printf("url:%s\n",domain);
    struct sockaddr_in dest;
    bzero(&dest,sizeof(dest));
    dest.sin_family = AF_INET;
    dest.sin_port = htons(53);
    dest.sin_addr.s_addr = inet_addr(DNS_SVR);
    // 连接 服务器
    int ret = connect(sockfd, (struct sockaddr *)&dest,sizeof(dest));
    printf("connect :%d\n",ret);
    // 准备 dns 相关数据 -- 头
    struct dns_header header = {0};
    dns_create_header(&header);

    // 准备 dns 相关数据 -- question
    struct dns_question question = {0};
    dns_create_question(&question,domain);

    char request[1024]  = {0};
	// 把 Header 与 question build 成 request 
    int req_len = dns_build_request(&header,&question,request);

	// 发送
    int slen = (int)sendto(sockfd, request, req_len, 0, (struct sockaddr*)&dest, sizeof(struct sockaddr));

	char buffer[1024] = {0};
	struct sockaddr_in addr;
	size_t addr_len = sizeof(struct sockaddr_in);
    // 需要等待----- 接收
    // 打印时间
    
	int n = (int)recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&addr, (socklen_t*)&addr_len);
	// 打印时间
		
	printf("recvfrom n : %d\n", n);
	struct dns_item *domains = NULL;
	// 解析接收
	dns_parse_response(buffer, &domains);

}
qifei@QF:~/0Voice/aysnc_dns$ ./sync_dns_client 
url:www.baidu.com
connect :0
---usedtime=[14] milliseconds.
recvfrom n : 63
www.baidu.com has address 36.152.44.96
        Time to live: 0 minutes , 0 seconds
www.baidu.com has address 36.152.44.95
        Time to live: 0 minutes , 0 seconds
url:tieba.baidu.com
connect :0
---usedtime=[6] milliseconds.
recvfrom n : 49
tieba.baidu.com has address 183.232.231.118
        Time to live: 0 minutes , 0 seconds
url:news.baidu.com
connect :0
---usedtime=[15] milliseconds.
recvfrom n : 80
news.baidu.com has address 39.156.68.124
        Time to live: 0 minutes , 0 seconds
news.baidu.com has address 112.34.111.125
        Time to live: 0 minutes , 0 seconds
news.baidu.com has address 183.232.232.207
        Time to live: 0 minutes , 0 seconds
url:zhidao.baidu.com
connect :0
---usedtime=[7] milliseconds.
recvfrom n : 50
zhidao.baidu.com has address 112.34.111.123
        Time to live: 0 minutes , 0 seconds
url:music.baidu.com
connect :0
---usedtime=[7] milliseconds.
recvfrom n : 49
music.baidu.com has address 120.53.205.35
        Time to live: 0 minutes , 0 seconds
url:image.baidu.com
connect :0
---usedtime=[15] milliseconds.
recvfrom n : 65
image.baidu.com has address 112.34.112.11
        Time to live: 0 minutes , 0 seconds
image.baidu.com has address 112.34.113.35
        Time to live: 0 minutes , 0 seconds
url:v.baidu.com
connect :0
---usedtime=[6] milliseconds.
recvfrom n : 77
v.baidu.com has address 180.76.54.189
        Time to live: 0 minutes , 0 seconds
v.baidu.com has address 180.76.139.133
        Time to live: 0 minutes , 0 seconds
v.baidu.com has address 180.76.236.81
        Time to live: 0 minutes , 0 seconds
url:map.baidu.com
connect :0
---usedtime=[7] milliseconds.
recvfrom n : 63
map.baidu.com has address 223.109.81.129
        Time to live: 0 minutes , 0 seconds
map.baidu.com has address 223.109.81.130
        Time to live: 0 minutes , 0 seconds
url:baijiahao.baidu.com
connect :0
---usedtime=[6] milliseconds.
recvfrom n : 53
baijiahao.baidu.com has address 223.109.81.200
        Time to live: 0 minutes , 0 seconds
url:xueshu.baidu.com
connect :0
---usedtime=[8] milliseconds.
recvfrom n : 66
xueshu.baidu.com has address 36.152.44.96
        Time to live: 0 minutes , 0 seconds
xueshu.baidu.com has address 36.152.44.95
        Time to live: 0 minutes , 0 seconds
url:cloud.baidu.com
connect :0
---usedtime=[6] milliseconds.
recvfrom n : 81
cloud.baidu.com has address 112.34.111.166
        Time to live: 0 minutes , 0 seconds
cloud.baidu.com has address 183.232.231.71
        Time to live: 0 minutes , 0 seconds
cloud.baidu.com has address 112.34.111.165
        Time to live: 0 minutes , 0 seconds
url:www.163.com
connect :0
---usedtime=[6] milliseconds.
recvfrom n : 77
www.163.com has address 36.150.145.247
        Time to live: 0 minutes , 0 seconds
www.163.com has address 36.150.145.244
        Time to live: 0 minutes , 0 seconds
www.163.com has address 36.150.145.245
        Time to live: 0 minutes , 0 seconds
url:open.163.com
connect :0
---usedtime=[7] milliseconds.
recvfrom n : 46
open.163.com has address 112.13.119.33
        Time to live: 0 minutes , 0 seconds
url:auto.163.com
connect :0
---usedtime=[15] milliseconds.
recvfrom n : 78
auto.163.com has address 36.156.5.248
        Time to live: 0 minutes , 0 seconds
auto.163.com has address 36.156.5.242
        Time to live: 0 minutes , 0 seconds
auto.163.com has address 36.156.5.240
        Time to live: 0 minutes , 0 seconds
url:gov.163.com
connect :0
---usedtime=[6] milliseconds.
recvfrom n : 77
gov.163.com has address 36.156.5.243
        Time to live: 0 minutes , 0 seconds
gov.163.com has address 36.156.5.249
        Time to live: 0 minutes , 0 seconds
gov.163.com has address 36.156.5.244
        Time to live: 0 minutes , 0 seconds
url:money.163.com
connect :0
---usedtime=[14] milliseconds.
recvfrom n : 79
money.163.com has address 36.156.5.240
        Time to live: 0 minutes , 0 seconds
money.163.com has address 36.156.5.241
        Time to live: 0 minutes , 0 seconds
money.163.com has address 36.156.5.249
        Time to live: 0 minutes , 0 seconds
url:sports.163.com
connect :0
---usedtime=[6] milliseconds.
recvfrom n : 80
sports.163.com has address 36.156.5.249
        Time to live: 0 minutes , 0 seconds
sports.163.com has address 36.156.5.240
        Time to live: 0 minutes , 0 seconds
sports.163.com has address 36.156.5.244
        Time to live: 0 minutes , 0 seconds
url:tech.163.com
connect :0
---usedtime=[7] milliseconds.
recvfrom n : 78
tech.163.com has address 36.156.5.243
        Time to live: 0 minutes , 0 seconds
tech.163.com has address 36.156.5.249
        Time to live: 0 minutes , 0 seconds
tech.163.com has address 36.156.5.250
        Time to live: 0 minutes , 0 seconds
url:edu.163.com
connect :0
---usedtime=[14] milliseconds.
recvfrom n : 77
edu.163.com has address 36.156.5.242
        Time to live: 0 minutes , 0 seconds
edu.163.com has address 36.156.5.241
        Time to live: 0 minutes , 0 seconds
edu.163.com has address 36.156.5.248
        Time to live: 0 minutes , 0 seconds
url:www.taobao.com
connect :0
---usedtime=[6] milliseconds.
recvfrom n : 64
www.taobao.com has address 36.156.208.231
        Time to live: 0 minutes , 0 seconds
www.taobao.com has address 36.156.208.230
        Time to live: 0 minutes , 0 seconds
url:q.taobao.com
connect :0
---usedtime=[14] milliseconds.
recvfrom n : 62
q.taobao.com has address 36.156.208.231
        Time to live: 0 minutes , 0 seconds
q.taobao.com has address 36.156.208.230
        Time to live: 0 minutes , 0 seconds
url:sf.taobao.com
connect :0
---usedtime=[6] milliseconds.
recvfrom n : 47
sf.taobao.com has address 203.119.144.26
        Time to live: 0 minutes , 0 seconds
url:yun.taobao.com
connect :0
---usedtime=[7] milliseconds.
recvfrom n : 48
yun.taobao.com has address 59.82.9.90
        Time to live: 0 minutes , 0 seconds
url:baoxian.taobao.com
connect :0
---usedtime=[14] milliseconds.
recvfrom n : 52
baoxian.taobao.com has address 59.82.31.182
        Time to live: 0 minutes , 0 seconds
url:www.tmall.com
connect :0
---usedtime=[15] milliseconds.
recvfrom n : 63
www.tmall.com has address 36.156.208.230
        Time to live: 0 minutes , 0 seconds
www.tmall.com has address 36.156.208.231
        Time to live: 0 minutes , 0 seconds
url:suning.tmall.com
connect :0
---usedtime=[9] milliseconds.
recvfrom n : 50
suning.tmall.com has address 203.119.169.156
        Time to live: 0 minutes , 0 seconds
url:www.tencent.com
connect :0
---usedtime=[6] milliseconds.
recvfrom n : 81
www.tencent.com has address 117.147.189.28
        Time to live: 0 minutes , 0 seconds
www.tencent.com has address 111.48.99.22
        Time to live: 0 minutes , 0 seconds
www.tencent.com has address 117.169.107.42
        Time to live: 0 minutes , 0 seconds
url:www.qq.com
connect :0
---usedtime=[15] milliseconds.
recvfrom n : 60
www.qq.com has address 183.194.238.19
        Time to live: 0 minutes , 0 seconds
www.qq.com has address 183.194.238.117
        Time to live: 0 minutes , 0 seconds
url:www.aliyun.com
connect :0
---usedtime=[6] milliseconds.
recvfrom n : 48
www.aliyun.com has address 106.11.172.51
        Time to live: 0 minutes , 0 seconds
url:www.ctrip.com
connect :0
---usedtime=[6] milliseconds.
recvfrom n : 63
www.ctrip.com has address 212.64.62.186
        Time to live: 0 minutes , 0 seconds
www.ctrip.com has address 212.64.62.187
        Time to live: 0 minutes , 0 seconds
url:hotels.ctrip.com
connect :0
---usedtime=[7] milliseconds.
recvfrom n : 50
hotels.ctrip.com has address 117.131.27.0
        Time to live: 0 minutes , 0 seconds
url:hotels.ctrip.com
connect :0
---usedtime=[6] milliseconds.
recvfrom n : 50
hotels.ctrip.com has address 117.131.27.0
        Time to live: 0 minutes , 0 seconds
url:vacations.ctrip.com
connect :0
---usedtime=[6] milliseconds.
recvfrom n : 53
vacations.ctrip.com has address 117.186.233.61
        Time to live: 0 minutes , 0 seconds
url:flights.ctrip.com
connect :0
---usedtime=[15] milliseconds.
recvfrom n : 51
flights.ctrip.com has address 117.186.233.61
        Time to live: 0 minutes , 0 seconds
url:trains.ctrip.com
connect :0
---usedtime=[14] milliseconds.
recvfrom n : 50
trains.ctrip.com has address 117.131.27.7
        Time to live: 0 minutes , 0 seconds
url:bus.ctrip.com
connect :0
---usedtime=[14] milliseconds.
recvfrom n : 47
bus.ctrip.com has address 117.131.27.7
        Time to live: 0 minutes , 0 seconds
url:car.ctrip.com
connect :0
---usedtime=[6] milliseconds.
recvfrom n : 47
car.ctrip.com has address 117.131.27.0
        Time to live: 0 minutes , 0 seconds
url:piao.ctrip.com
connect :0
---usedtime=[26] milliseconds.
recvfrom n : 48
piao.ctrip.com has address 117.131.27.0
        Time to live: 0 minutes , 0 seconds
url:tuan.ctrip.com
connect :0
---usedtime=[13] milliseconds.
recvfrom n : 48
tuan.ctrip.com has address 117.186.233.27
        Time to live: 0 minutes , 0 seconds
url:you.ctrip.com
connect :0
---usedtime=[14] milliseconds.
recvfrom n : 47
you.ctrip.com has address 117.131.27.7
        Time to live: 0 minutes , 0 seconds
url:g.ctrip.com
connect :0
---usedtime=[15] milliseconds.
recvfrom n : 45
g.ctrip.com has address 117.186.233.61
        Time to live: 0 minutes , 0 seconds
url:lipin.ctrip.com
connect :0
---usedtime=[22] milliseconds.
recvfrom n : 49
lipin.ctrip.com has address 117.186.233.61
        Time to live: 0 minutes , 0 seconds
url:ct.ctrip.com
connect :0
---usedtime=[14] milliseconds.
recvfrom n : 46
ct.ctrip.com has address 117.131.27.0
        Time to live: 0 minutes , 0 seconds

43 个 url

url时间
14
6
15
7
7
15
6
7
6
8
6
6
7
15
6
14
6
7
14
6
14
6
7
14
15
9
6
15
6
6
7
6
6
15
14
14
6
26
13
14
15
22
14
合计448

例子: 异步DNS请求

异步请求主要使用epoll

commit()
thread_callback()
init_ctx()
destroy()

  1. 初始化的时候先准备好 epoll epfd 方便 监听 异步的返回消息
  2. 接收到 异步返回消息的时候,调用回调函数来解析返回的消息。因此必须要先指定回调函数
  3. 实际提交请求 用 commit
  4. 销毁 用 destroy

Commit 细节:
1. 创建Socket() bind();
2. connect – 为什么 udp 需要 connect? connect 用于探测,打通链路
3. 准备好 DNS 协议
4. sendto()
同步方案 : recvfrom 等待
异步方案:发送就返回,把 fd 加入到 epoll 里面
创建一个线程,专门去检查 epoll 的触发返回,并执行解析。

代码:

// 1. 初始化  -- 创建 epoll  创建 thread
int dns_async_client_init(struct async_context *ctx,void* callback){
// 1
// epoll
     if( ctx == NULL )  return  -EINVAL;

     ctx->epfd = epoll_create(1);

	 int ret = pthread_create(&ctx->thid,NULL,callback,ctx);
	 if(ret){
		perror("pthread_create error");
		return -1;
	 }
	 usleep(1);//child go first
	 return 0;
}
//===============================
// == 单个线程循环执行-主要负责从epoll 中recv
void dns_async_client_callback(void *arg){
	struct async_context *ctx = (struct async_context*)arg;
	printf("callbak:epfd:%d\n",ctx->epfd);
    printf("callbak:thid:%ld\n",ctx->thid);
	while(1){
		//printf("callbak.\n");
		struct epoll_event events[ASYNC_EVENT_LENGTH];
		int nready = epoll_wait(ctx->epfd,events,ASYNC_EVENT_LENGTH,-1);
		//printf("nready:%d\n", nready);
		if (nready < 0) {
			if (errno == EINTR || errno == EAGAIN) {
				continue;
			} else {
				break;
			}
		} else if (nready == 0) {
			continue;
		}

		//printf("nready:%d\n", nready);
    	int i = 0;
		for(i = 0;i < nready; i++)
		{
			struct ep_arg *arg = (struct ep_arg *)events[i].data.ptr;
            int sockfd = arg->sockfd;
			//printf("sockfd:%d\n",sockfd);
			char buffer[1024] = {0};
			struct sockaddr_in addr;
			size_t addr_len = sizeof(struct sockaddr_in);
				
			int n = (int)recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&addr, (socklen_t*)&addr_len);
		
		    printf("===================\n");
			printf("recvfrom n : %d\n", n);
			struct dns_item *domains = NULL;
			dns_parse_response(buffer, &domains);
			printf("===================\n");

		}
	}
}
// ================= commit ======
int dns_async_client_commit(struct async_context *ctx,const char *domain)
{
	// 1. 创建 socket()
	//2.bind() 连接 Connect()  为什么 UDP 需要 connect 
	//3. dns protocol
	//4. sendto()
	//5. 同步  recvfrom  卡在这边  异步方案: 发送完就返回,fd 加到epoll 里面
	int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd < 0){
        perror("create socket failed\n");
        exit(-1);
    }
    //printf("url:%s\n",domain);
    struct sockaddr_in dest;
    bzero(&dest,sizeof(dest));
    dest.sin_family = AF_INET;
    dest.sin_port = htons(53);
    dest.sin_addr.s_addr = inet_addr(DNS_SVR);

    int ret = connect(sockfd, (struct sockaddr *)&dest,sizeof(dest));
    //printf("connect :%d\n",ret);

    struct dns_header header = {0};
    dns_create_header(&header);

    struct dns_question question = {0};
    dns_create_question(&question,domain);

    char request[1024]  = {0};
    int req_len = dns_build_request(&header,&question,request);
    int slen = (int)sendto(sockfd, request, req_len, 0, (struct sockaddr*)&dest, sizeof(struct sockaddr));

    struct ep_arg *arg = (struct ep_arg*)calloc(1,sizeof(struct ep_arg));
    if(arg == NULL) return -1;
    arg->sockfd = sockfd;

	struct epoll_event ev;
	ev.data.ptr = arg;
	ev.events = EPOLLIN;

	epoll_ctl(ctx->epfd,EPOLL_CTL_ADD,sockfd,&ev);
	//printf(" epoll_ctl ADD: sockfd->%d, ret:%d\n", sockfd, ret);
	return ret;
    //close(sockfd);
	//free(arg);
}
//======================
int dns_async_client_destory(struct async_context *ctx){
    
    if( ctx == NULL )  return  -EINVAL;

	 close(ctx->epfd);

     pthread_cancel(ctx->thid);

	 return 0;
}
//=================main==
int main(int argc,char *argv[])
{
	struct async_context ctx;
	int res = dns_async_client_init(&ctx,dns_async_client_callback);
	//printf("epfd:%d\n",ctx.epfd);
    //printf("thid:%ld\n",ctx.thid);
    if(res == -1 )
	{
		printf("error\n");
	}
    int count = sizeof(domain)/ sizeof(domain[0]);
    int i = 0;
    for(i=0;i<count;i++){
        dns_async_client_commit(&ctx, domain[i]);
    }
	getchar();
}

有什么更好的方式能减轻 单个线程的CPU的压力。就需要协程。

为什么需要有协程?
1.同步的编程方式,异步的性能。
2. 比线程 和进程更轻量级的线程。具有自我调度功能的。

文章参考与<零声教育>的C/C++linux服务期高级架构系统教程学习:
服务器高级架构体系:
https://ke.qq.com/course/417774?flowToken=1010783

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值