9. Linux下实现简单的socket通讯

news2024/11/15 23:57:35

本文简单介绍了UDP传输层协议,并在Linux下实现简单的socket通讯

一、UDP

UDP(User Datagram Protocol,用户数据报协议)是一种无连接的传输层协议,它不保证数据包的可靠性和顺序。UDP在IP协议的基础上增加了简单的差错检测功能,但是没有流量控制、拥塞控制等复杂机制。
相对于TCP,UDP具有以下优点:

  • 速度快:由于没有建立连接和维护状态等额外开销,在网络带宽较好时UDP可以实现更高的吞吐量和更低的延迟。
  • 简单:UDP协议非常简单,只提供了最基本的数据传输功能,因此实现起来比TCP更容易。
  • 支持广播和多播:UDP支持向多个主机发送同一份数据报文,可以用于组播或广播应用中。
  • 实时性强:由于没有拥塞控制等机制,UDP能够实现较为精准地时间同步、音视频传输等实时应用场景。

总之,在需要快速传输数据且可靠性要求不高的情况下,选择使用UDP会比TCP更合适。
在这里插入图片描述

二、实现简单的socket通讯

注意本文是在Linux下实现,若要在window下实现socket需要链接库,参考Windows的socket通讯

在这里插入图片描述

#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>

//window下的头文件
// #include <winSock2.h>
// #include <windows.h>
// #include <sys/types.h>  

//Linux下的头文件
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


#define DNS_SERVER_PORT     53
#define DNS_SERVER_IP      "114.114.114.114"
#define DNS_HOST			0x01
#define DNS_CNAME			0x05
#define socklen_t           int

struct dns_header{
    unsigned short id;
    unsigned short flags;

    unsigned short questions;
    unsigned short answer;

    unsigned short authority;
    unsigned short additional;
};

struct dns_question{
    int length;
    unsigned short qtype;
    unsigned short qclass;
    unsigned char *name;
};

struct dns_item {
	char *domain;
	char *ip;
};

//创建头部
int dns_create_header(struct dns_header *header){
    if (header == NULL) return -1;
    memset(header,0,sizeof(struct dns_header));

    srand(time(NULL));
    header->id=rand();

    //htons()用于将16位整数由主机字节序转换为网络字节序
    header->flags=htons(0x0100);
    header->questions=htons(1);

    return 0;
}

创建正文
int dns_create_question(struct dns_question *question,const char *hostname){
    if (question == NULL || hostname == NULL) return -1;
    memset(question,0,sizeof(struct dns_question));

    //因为hostname末尾还有结束标记
    question->name=(char *)malloc(strlen(hostname)+2);
    if (question->name == NULL){
        return -2;
    }

    question->length=strlen(hostname)+2;

    question->qtype=htons(1);
    question->qclass=htons(1);

    //若hostname=www.baidu.com,则question->name(查询名)为3www5baidu3com0
    const char delim[2]="."; //C语言中字符串以空字符'\0'作为结尾,因此在定义字符数组时需要额外留出一个元素来存储结尾标志。
    char *qname=question->name;

    char *hostname_dup=strdup(hostname);//将字符串复制到新的内存空间,并返回指向该空间的指针
    char *token=strtok(hostname_dup,delim);

    while (token != NULL){
        size_t len=strlen(token);

        //qname第一位放len,如3
        *qname=len; 
        qname++;

        //放入字母,如www\0,len+1代表加上结束符\0
        strncpy(qname,token,len+1);
        qname+=len;

        token=strtok(NULL,delim);//在后续调用时可直接传入NULL作为第一个参数继续处理上一次未处理完的字符串。

    }

    free(hostname_dup);
}

//构建查询请求
//将DNS消息头部分和查询问题部分按照规定格式打包到缓冲区中,形成一个完整的DNS查询请求报文。
int dns_bulid_requestion(struct dns_header *header,struct dns_question *question,char *request,int rlen){
    if (header == NULL || question == NULL || request == NULL) return -1;
    memset(request,0,rlen);

    //复制header到request
    memcpy(request,header,sizeof(struct dns_header));
    int offset=sizeof(struct dns_header); 

    //复制question到request
    memcpy(request+offset,question->name,sizeof(struct dns_question));
    offset+=question->length;

    memcpy(request+offset,&question->qtype,sizeof(question->qtype));
    offset+=sizeof(question->qtype);

    memcpy(request+offset,&question->qclass,sizeof(question->qclass));
    offset+=sizeof(question->qclass);

    //返回长度
    return offset;
}

//'''''''''''''''''''''''''以下三个函数用于解析'''''''''''''''''''''''''''''''''''''''''''''''
//判断一个DNS记录中的域名是否使用了指针(Pointer)
static int is_pointer(int in) {
	return ((in & 0xC0) == 0xC0);
}

//将DNS查询或响应报文中的域名字段解析成普通字符串。
static void dns_parse_name(unsigned char *chunk, unsigned char *ptr, char *out, int *len) {

	int flag = 0, n = 0, alen = 0;
	char *pos = out + (*len);

	while (1) {

		flag = (int)ptr[0];
		if (flag == 0) break;

		if (is_pointer(flag)) {
			
			n = (int)ptr[1];
			ptr = chunk + n;
			dns_parse_name(chunk, ptr, out, len);
			break;
			
		} else {

			ptr ++;
			memcpy(pos, ptr, flag);
			pos += flag;
			ptr += flag;

			*len += flag;
			if ((int)ptr[0] != 0) {
				memcpy(pos, ".", 1);
				pos += 1;
				(*len) += 1;
			}
		}
	
	}
	
}

//用于解析从服务器返回的DNS响应报文,并提取出其中包含的信息,如IP地址等。
static int dns_parse_response(char *buffer, struct dns_item **domains) {

	int i = 0;
	unsigned char *ptr = buffer;

	ptr += 4;
	int querys = ntohs(*(unsigned short*)ptr);

	ptr += 2;
	int answers = ntohs(*(unsigned short*)ptr);

	ptr += 6;
	for (i = 0;i < querys;i ++) {
		while (1) {
			int flag = (int)ptr[0];
			ptr += (flag + 1);

			if (flag == 0) break;
		}
		ptr += 4;
	}

	char cname[128], aname[128], ip[20], netip[4];
	int len, type, ttl, datalen;

	int cnt = 0;
	struct dns_item *list = (struct dns_item*)calloc(answers, sizeof(struct dns_item));
	if (list == NULL) {
		return -1;
	}

	for (i = 0;i < answers;i ++) {
		
		bzero(aname, sizeof(aname));
		len = 0;

		dns_parse_name(buffer, ptr, aname, &len);
		ptr += 2;

		type = htons(*(unsigned short*)ptr);
		ptr += 4;

		ttl = htons(*(unsigned short*)ptr);
		ptr += 4;

		datalen = ntohs(*(unsigned short*)ptr);
		ptr += 2;

		if (type == DNS_CNAME) {

			bzero(cname, sizeof(cname));
			len = 0;
			dns_parse_name(buffer, ptr, cname, &len);
			ptr += datalen;
			
		} else if (type == DNS_HOST) {

			bzero(ip, sizeof(ip));

			if (datalen == 4) {
				memcpy(netip, ptr, datalen);
				inet_ntop(AF_INET , netip , ip , sizeof(struct sockaddr));

				printf("%s has address %s\n" , aname, ip);
				printf("\tTime to live: %d minutes , %d seconds\n", ttl / 60, ttl % 60);

				list[cnt].domain = (char *)calloc(strlen(aname) + 1, 1);
				memcpy(list[cnt].domain, aname, strlen(aname));
				
				list[cnt].ip = (char *)calloc(strlen(ip) + 1, 1);
				memcpy(list[cnt].ip, ip, strlen(ip));
				
				cnt ++;
			}
			
			ptr += datalen;
		}
	}

	*domains = list;
	ptr += 2;

	return cnt;
	
}
//使用DNS协议向指定域名domain发送查询请求,并接收并处理响应结果。
int dns_client_commit(const char *domain){

    //Socket是一种提供网络通信功能的编程接口或API,它允许不同的计算机之间通过网络进行数据传输。
    // 创建socket
    int sockfd=socket(AF_INET,SOCK_DGRAM,0);
    if (sockfd <0){
        return -1;
    }

    // 绑定地址和端口号
    struct sockaddr_in servaddr={0};
    servaddr.sin_family =AF_INET;
    servaddr.sin_port=htons(DNS_SERVER_PORT);
    servaddr.sin_addr.s_addr = inet_addr(DNS_SERVER_IP);

    //连接服务器
   int ret= connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr));
   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 length=dns_bulid_requestion(&header,&question,request,1024);

    // 发送消息
    sendto(sockfd,request,length,0,(struct sockaddr *)&servaddr,sizeof(struct sockaddr));

    //接收回复
    char response[1024]={0};
    struct sockaddr_in addr;
    size_t addr_len=sizeof(struct sockaddr_in);
    int n=recvfrom(sockfd,response,sizeof(response),0,(struct sockaddr *)&addr,(socklen_t*)&addr_len);

    //解析
	struct dns_item *dns_domain = NULL;
	dns_parse_response(response, &dns_domain);

	free(dns_domain);
    return n;
}

int main(int argc ,char *argv[]){
    if (argc<2) return -1;
    dns_client_commit(argv[1]);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/564255.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

es 四 快速入门****

目录 查看集群状态 **颜色&#xff1a; 查看集群索引 **简单的索引操作 kibana 创建索引模式 Es 存储 文档 json数据 查看集群状态 get /_cat/health 带上表头 get /_cat/health?v **颜色&#xff1a; 绿色: 主分片副本分片可用 黄色: 主分片可用、副本分片不可用 红…

Java 与数据结构(6):快速排序

ChatGPT 中文指南(大全) 内容包含&#xff1a;如何开通chatgpt、chatgpt的同类站点、prompts 、AI绘图、ChatGPT 工具、相关报告论文、ChatGPT应用项目等 链接&#xff1a;ChatGPT 中文指南(大全) 指令指南&#xff0c;精选资源清单&#xff0c;更好的使用 chatGPT 让你的生产力…

C++线程池介绍和C++代码实现

1、介绍 1.1 线程池应用场景 在进行创建线程任务时&#xff0c;如果需要频繁的创建线程、销毁线程&#xff0c;这样会极大地降低效率&#xff0c;因为创建线程也是需要时间的&#xff0c;一个完整的线程处理运行时间包括&#xff1a;线程的创建时间、线程运作时间、线程的销毁…

【C++】-string的介绍以及使用(迭代器的介绍和使用)

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树 ❤️‍&#x1fa79;作者宣言&#xff1a;认真写好每一篇博客 &#x1f4a8;作者gitee:gitee &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 如 果 你 喜 欢 作 者 的 文 章 &#xff0c;就 给 作 者 点…

谈谈国产化CRM系统市场前景与发展趋势

随着数字化时代的到来&#xff0c;CRM系统已经成为企业管理中不可或缺的一部分。在过去&#xff0c;大多数企业都选择使用海外CRM系统&#xff0c;比如Salesforce、SAP等&#xff0c;但随着国内CRM系统的逐渐发展&#xff0c;越来越多的企业开始将目光转向了国产CRM系统。 一、…

Qt--自定义控件

写在前面 Qt中提供了应用在各种场景的控件&#xff0c;使开发人员在实际工作中选择。但有些特定的场合中这些控件并不满足需要时&#xff0c;Qt允许使用自定义的控件。 例&#xff1a;我们在工作中有这样一种需求&#xff0c;点击按钮会根据一些其他状态来显示不同的图片&…

在外远程登录局域网下的象过河ERP管理系统,无需公网IP

文章目录 概述1.查看象过河服务端端口2.内网穿透3. 异地公网连接4. 固定公网地址4.1 保留一个固定TCP地址4.2 配置固定TCP地址 5. 使用固定地址连接 转发自CSDN远程穿透的文章&#xff1a;公网远程访问公司内网象过河ERP系统「内网穿透」 概述 ERP系统对于企业来说重要性不言而…

3D可视化智慧档案馆一体建设平台设计的主要依据

1、《中华人民共和国档案法》 2、《中华人民共和国档案实施办法》 3、GB/T 9386-1988《计算机软件测试文件编制规范》 4、GB/T 15532-1995《计算机软件单元测试规范》 5、GB/T 30961-2014 嵌入式软件质量度量 6、GB2421-89 电工电子产品基本环境试验规程 7、GB16796-2009…

【1377. T 秒后青蛙的位置】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给你一棵由 n 个顶点组成的无向树&#xff0c;顶点编号从 1 到 n。青蛙从 顶点 1 开始起跳。规则如下&#xff1a; 在一秒内&#xff0c;青蛙从它所在的当前顶点跳到另一个 未访问 过的顶点&#xf…

网终安全技术(刘化君)课后被略的答案

目录 8.HTTP客户机与Wb服务器通信通常会泄露哪些信息&#xff1f; 9.在TCP连接建立的3次握手阶段&#xff0c;攻击者为什么可以成功实施SYN Flood攻击&#xff1f;在实际中&#xff0c;如何防范此类攻击&#xff1f; 常用的网络漏洞扫描技术有哪几种&#xff1f;试举例说明。…

Visual Studio 2010环境新建C工程项目

新建C工程项目 文章目录 新建C工程项目前言1、新建空项目2、编写程序2.1 Hello World2.1 执行.exe文件 3、总结 前言 学习C语言使用的编译器比较多&#xff0c;常见的有VC6.0、Dev-C、Visual Studio、CodeBlocks等环境软件。 Visual Studio和CodeBlocks的功能就稍微强大很多&a…

MySQL_5 有丶牛逼的查询语句

目录 一、分组查询 1.基本语法 : 2.代码演示 : 二、分页查询 1.基本语法 : 2.代码演示 : 三、多表查询 1.定义 : 2.语法 : 3.演示 : 四、嵌套查询 1.定义 : 2.单行子查询 : 1 特点 2 演示 3.多行子查询 : 1 特点 2 演示 4.临时表 : 1 定义 2 演示 5.多列子查询 …

Emacs之实时渲染markdown(九十五)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

Web安全常见攻击

前言 本篇主要简单介绍在 Web 领域几种常见的攻击手段。 1. Cross Site Script&#xff08;XSS跨站脚本攻击) 首先插播一句&#xff0c;为毛叫 XSS&#xff0c;缩写明显是 CSS 啊&#xff1f;没错&#xff0c;为了防止与我们熟悉的 CSS&#xff08;Cascading Style Sheets&am…

类ChatGPT的各种语言大模型LLM开源Github模型集合​

作为开发人员&#xff0c;面对堪称科技奇点爆发的ChatGPT&#xff0c;我们如何应对。当然是努力跟进&#xff0c;虽然ChatGPT不开源&#xff0c;但是有诸多不输ChatGPT的各类语言大模型LLM有分享。我们筛选出其中影响力较大的各个开源Github仓库&#xff0c;收录到 类ChatGPT的…

由浅入深Dubbo网络通信协议大全

目录 1 网络通信协议1.1 dubbo协议1.2 rmi协议1.3 hessian协议1.4 http协议1.5 webservice协议1.6 thrift协议1.7 rest协议1.8 grpc协议1.9 memcached协议1.10 redis协议 2 序列化实现剖析 1 网络通信协议 在之前的内容中&#xff0c;我们讲解了消费者端服务发现与提供者端服务…

局部最小值问题

局部最小值问题 自写&#xff1a; // arr 相邻的数不相等&#xff01; 返回一个局部最小的下标public static int oneMinIndex(int[] arr) {if(arr null || arr.length 0) {return -1;}if(arr.length 1) {return 0;}int L 0;int R arr.length - 1;if(arr[L] < arr[L 1…

C++判断大端小端

C判断大端小端 1. 基础知识 大端小端其实表示的是数据在存储器中的存放顺序。 大端模式&#xff1a;数据的高字节存放在内存的低地址中&#xff0c;而低字节则存放在高地址中。地址由小到大增加&#xff0c;数据则从高位向低位存放&#xff0c;这种存放方式符合人类的正常思维…

Hadoop/HbBase/Hive/HDFS/MapReduce都是什么?

目录 一图胜万言&#xff01;&#xff01; 解释说明 1. hadoop 2. hive 3. hbase 总结 一图胜万言&#xff01;&#xff01; 解释说明 1. hadoop 它是一个分布式计算分布式文件系统&#xff0c;前者其实就是 MapReduce&#xff0c;后者是 HDFS 。后者可以独立运行&…

特瑞仕|关于无线射频

无线射频&#xff08;Radio Frequency, RF&#xff09;是指在一定频率范围内&#xff0c;通过无线电波进行通信和传输信息的技术。随着移动通信、物联网、智能家居等领域的不断发展&#xff0c;无线射频技术已经成为现代社会中不可或缺的一部分。本文将从以下几个方面对无线射频…