百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

tcp和socket有什么关系,与http又有什么联系?

liebian365 2024-12-31 12:45 23 浏览 0 评论

最近项目中需要自己去实现一个http的接口。所以趁这个机会跟大家讲一下http和socket的关系,以及与TCP又有什么联系。

首先大家一定要明确一点,在网络分层架构当中,HTTP协议是属于应用层的,tcp协议是属于传输层的,也就是说它们是一种协议,是通信双方规定的一种规则,没有这种规则,两台主机就无法完成通信。

而根据我们曾经所学的知识可以知道,两台主机要完成通信,必须在传输层规定一套相同的协议,至于要不要在传输层就建立连接,因协议而异,tcp协议是需要建立连接的,而udp就不需要。至于tcp和udp的区别,不在本文的讨论范围,所以暂时不论。因为现在传输数据大部分都是使用tcp协议,所以tcp协议是非常重要的,必须要掌握。

传输层使用tcp协议发送数据的话,首先要完成TCP的三次握手过程。为什么要完成三次握手过程?为了保证数据传输的准确性,就是让数据可以准确无误的传输到另一台主机。至于如何完成三次握手过程,这个知识点在网上有非常多的资料大家可以去百度看看。

而三次握手建立连接,这更像是一种理论的过程,也就是说我告诉你三次握手的过程,但是你要帮我实现这个过程,那怎么实现呢?这个具体实现的过程就是靠socket来实现的,socket是操作系统为tcp封装的一整套建立连接,发送数据,断开连接的过程,它是对外提供的一个接口。注意我这里说的是操作系统,也就是说不同的操作系统封装的socket接口函数可能有所不同,这一点大家需要注意。在linux上使用最多的socket函数一般有socket()bind()listen()accept()connect()close()这几个函数,在window上略有不同。

到这里不知道大家明白了没有,tcp只是传输层上的一个协议,是通信双方互相规定的一种协议,而socket就是这种协议的具体实现过程。所以如果你足够牛逼,你可以自己给通信双方的两台主机制定一套属于自己的传输层协议,然后自己写代码实现这个过程。但一般没有人会这么做,为什么呢?因为这个工作量非常的恐怖,这个恐怖不是体现在制定协议以及写代码实现的这个过程,这个恐怖是体现在必须为通信双方的两台机子都适配这种协议。服务端还好说,是都是自己的机子,控制权都在自己手上,而且一般都只使用linux系统,但是到客户端就彻底宕机了,客户端肯定不是就一台的,是千千万万台,而且还有不同的操作系统,你要不就自己去一个个系统去适配你的协议,要不就是去斡旋各大操作系统厂商写入你的协议。所以这样的事也只有全球有影响力的企业,有影响力的组织才可以完成的,一般人不可能,也没必要。

上面说了那么多,就是告诉同学们,通信双方要完成通信,要先在传输层利用tcp协议建立连接。连接建立完成之后,就可以开始发送数据了,那么接着问题来了。

一、如果我要发送不同结构,不同规则的数据的话,我要怎么发。

二、我发出去的数据,肯定会收到一个回复,那么我怎么处理这个回来的数据。

如果以上两个问题,大家不是很明白,没关系,接下去往下看,你可能就明白了。

基于以上两个问题,就需要在应用层上制定一套属于通信双方自己的协议了,而这套协议是规定双方发送接收的数据规则。http就是应用层一个非常经典的协议,它是因特网上应用最为广泛的一种网络传输协议,所有的WWW文件都必须遵守这个标准。当然应用层协议不仅仅只有http,还有telnet,ftp,smtp等等这些都是非常经典的应用层协议,通信双方都必须按照协议规定的数据格式来发送和接收。而且根据双方发送数据的需求,还可以制定属于自己的应用层协议,来满足自己的本地化需求。只要你有需求,应用层协议随便你添加。

那么为什么添加传输层协议难如登天,而添加应用层协议却那么简单呢?

简单一句话概括就是:传输层协议是操作系统级别的,而应用层协议是应用软件级别的。

所以添加一个传输层协议一定是一个浩大的工程,因为要在操作系统级别上更新。而添加一个应用层协议就比较简单了,因为只是添加在你所开发的软件或者app的客户端和服务端上。

用最生活化的例子来比喻,假如要从A地到B地,那么怎么过去呢,肯定需要修建一条路,那么修建这条路所需要的设计图纸就相当于tcp,而工人们修建的过程就相当于socket,不能盲目修建,必须基于设计图纸来修建,而socket也必须基于tcp协议的理论,而修建一条道路是耗资巨大的工程,所以不可能随便的添加传输层协议。一旦道路修建完成,你可以采用各种方式过去,走路、跑步、骑自行车、开小车等等都可以,只要你开心,你要爬过去都可以,而采用何种方式过去就是应用层协议,http是其中的一种过去方式。

总的来说,tcp是传输层的一个协议,而socket是这个协议的封装,可以对外提供接口,让应用程序调用,而http是应用层的一个协议,是一种对数据的封装。发起http请求的时候,底层的传输层要完成两台机子的连接,就是tcp三次握手完成连接。

更多精彩内容,欢迎关注同名公众:一点月光

以下我给出了一个http封装的例子,只有客户端,是当时做项目的时候写,大家可以参考参考

//http接口
int http_post_openapi(const char *pIP, const char *pServ, int port, const char *pSendValue, char *pRecvValue)
{
	int sockfd, ret, i, h;
	struct sockaddr_in servaddr;
    char szHttpHead[1024], buf[8192], szSendValueLength[128],szSendBuffer[4096];
	int iLen = 0;
	fd_set   t_set1;
	struct timeval  tv;

	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
		printf("创建网络连接失败,本线程即将终止---socket error!\n");
		exit(0);
	};

	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(port);
	if (inet_pton(AF_INET, pIP, &servaddr.sin_addr) <= 0 ){
		printf("创建网络连接失败,本线程即将终止--inet_pton error!\n");
		exit(0);
	};

	if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0){
		printf("连接到服务器失败,connect error!\n");
		exit(0);
	}
	printf("与远端建立了连接\n");

	if (pSendValue == NULL || pRecvValue == NULL)
	{
		close(sockfd);
		printf("\n传入的pSendValue或者pRecvValue为空!!!\n");
		return -1;
	}	

	char szSendConver[4096] = {0};
	TrimAll(pSendValue, szSendConver);
	
	iLen = strlen(szSendConver);

	memset(szSendValueLength, 0, 128);
	sprintf(szSendValueLength, "%d", iLen);
	printf("szSendValueLength after sprintf is :%s\n", szSendValueLength);

	memset(szHttpHead, 0, 256);

	strcat(szHttpHead, "POST ");
	strcat(szHttpHead, pServ);
	strcat(szHttpHead, " HTTP/1.1\r\n");
	strcat(szHttpHead, "Host: ");
	strcat(szHttpHead, pIP);
	strcat(szHttpHead, ":");
	char cPort[6];
	sprintf(cPort,"%ld",port);
	strcat(szHttpHead, cPort);
	strcat(szHttpHead, "\r\n");
	strcat(szHttpHead, "User-Agent: Apache-HttpClient/4.1.1\r\n");
	strcat(szHttpHead, "Accept: */*\r\n");
	strcat(szHttpHead, "Content-Length: ");
	strcat(szHttpHead, szSendValueLength);
	strcat(szHttpHead, "\r\n");
	strcat(szHttpHead, "Content-Type: application/json; charset=UTF-8");
	printf("szSendValueLength is :%s\n", szSendValueLength);

	strcat(szHttpHead, "\r\n\r\n");
	memset(szSendBuffer, 0, 4096);
	strcat(szSendBuffer, szHttpHead);
	strcat(szSendBuffer, szSendConver);

	strcat(szSendBuffer, "\r\n\r\n");
	printf("Print SendBuffer before write :\n%s\n",szSendBuffer);

	ret = write(sockfd,szSendBuffer,strlen(szSendBuffer));
	if (ret < 0) {
		printf("发送失败!错误代码是%d,错误信息是'%s'\n",errno, strerror(errno));
		exit(0);
	}else{
		printf("消息发送成功,共发送了%d个字节!\n\n", ret);
	}

	FD_ZERO(&t_set1);
	FD_SET(sockfd, &t_set1);

	memset(buf, 0, sizeof(buf));
	i= read(sockfd, buf, sizeof(buf)-1);
	if (i==0)
	{
		close(sockfd);
		printf("读取数据报文时发现远端关闭,该线程终止!\n");
		return -1;
	}

	close(sockfd);
	//在此处找到HTTP的RESPONSE结果码,如果为200,则成功,截取包体赋值到pRecvBuff;否则返回-1。
	char *pRet = NULL;
	char *pStart = NULL;
	char *pEnd = NULL;
	//pRet = strstr(buf, "HTTP/1.1 200 OK");
	pRet = strstr(buf, "HTTP/1.1 200");
	if(!pRet)
	{
		cout << "HTTP Response Error!!!" << endl;
		return -1;
	}

	string sRecv;
	utf82gb(buf, sRecv);
	printf("sRecv is :\n%s\n", sRecv.c_str());

	memset(buf, 0, sizeof(buf));
	strncpy(buf, sRecv.c_str(), sRecv.length());
	
	pStart = strstr(buf, "{");
	printf("pStart address is :0x%x\n", pStart);

	pEnd = strrchr(buf, '}') + 1;
	printf("pEnd address is :0x%x\n", pStart);
	//

	if(pStart != NULL && pEnd != NULL)
	{
		strncpy(pRecvValue, pStart, (int)(pEnd - pStart));
		//userlog("消息返回成功-消息,请求消息:\n%s\n ******** 返回消息:\n%s\n", szSendBuffer, buf);
	}
	else
	{
		printf("\nbuf中未找到匹配的数据!!!\n");
		userlog("消息返回失败-消息,请求消息:\n%s\n ******** 返回消息:\n%s\n", szSendBuffer, buf);
		return -2;
	}
	
	return 0;
}

相关推荐

精品博文嵌入式6410中蓝牙的使用

BluetoothUSB适配器拥有一个BluetoothCSR芯片组,并使用USB传输器来传输HCI数据分组。因此,LinuxUSB层、BlueZUSB传输器驱动程序以及B...

win10跟这台计算机连接的前一个usb设备工作不正常怎么办?

前几天小编闲来无事就跑到网站底下查看粉丝朋友给小编我留言询问的问题,还真的就给小编看到一个问题,那就是win10跟这台计算机连接的一个usb设备运行不正常怎么办,其实这个问题的解决方法时十分简单的,接...

制作成本上千元的键盘,厉害在哪?

这是稚晖君亲自写的开源资料!下方超长超详细教程预警!!全文导航:项目简介、项目原理说明、硬件说明、软件说明项目简介瀚文智能键盘是一把我为自己设计的——多功能、模块化机械键盘。键盘使用模块化设计。左侧的...

E-Marker芯片,USB数据线的“性能中枢”?

根据线缆行业的研究数据,在2019年搭载Type-C接口的设备出货量已达到20亿台,其中80%的笔记本电脑和台式电脑采用Type-C接口,50%的智能手机和平板电脑也使用Type-C接口。我们都知道,...

ZQWL-USBCANFD二次开发通讯协议V1.04

修订历史:1.功能介绍1.1型号说明本文档适用以下型号:  ZQWL-CAN(FD)系列产品,USB通讯采用CDC类实现,可以在PC机上虚拟出一个串口,串口参数N,8,1格式,波特率可以根据需要设置(...

win10系统无法识别usb设备怎么办(win10不能识别usb)

从驱动入手,那么win10系统无法识别usb设备怎么办呢?今天就为大家分享win10系统无法识别usb设备的解决方法。1、右键选择设备管理器,如图:  2、点击更新驱动程序,如图:  3、选择浏览...

微软七月Win8.1可选补丁有内涵,含大量修复

IT之家(www.ithome.com):微软七月Win8.1可选补丁有内涵,含大量修复昨日,微软如期为Win7、Win8.1发布7月份安全更新,累计为6枚安全补丁,分别修复总计29枚安全漏洞,其中2...

如何从零开始做一个 USB 键盘?(怎么制作usb)

分两种情况:1、做一个真正的USB键盘,这种设计基本上不涉及大量的软件编码。2、做一个模拟的USB键盘,实际上可以没有按键功能,这种的需要考虑大量的软件编码,实际上是一个单片机。第一种设计:买现成的U...

电脑识别U盘失败?5个实用小技巧,让你轻松搞定USB识别难题

电脑识别U盘失败?5个实用小技巧,让你轻松搞定USB识别难题注意:有些方法会清除USB设备里的数据,请谨慎操作,如果不想丢失数据,可以先连接到其他电脑,看能否将数据复制出来,或者用一些数据恢复软件去扫...

未知usb设备设备描述符请求失败怎么解决

出现未知daousb设备设备描述符请求失du败解决办zhi法如下:1、按下Windows+R打开【运行】;2、在版本运行的权限输入框中输入:services.msc按下回车键打开【服务】;2、在服务...

读《飘》47章20(飘每章概括)

AndAhwouldn'tleaveMissEllen'sgrandchildrenfornotrashystep-patobringup,never.Here,Ah...

英翻中 消失的过去 37(消失的英文怎么说?)

翻译(三十七):消失的过去/茱迪o皮考特VanishingActs/JodiPicoult”我能做什么?“直到听到了狄利亚轻柔的声音,我才意识到她已经在厨房里站了好一会儿了。当她说话的时候,...

RabbitMQ 延迟消息实战(rabbitmq如何保证消息不被重复消费)

现实生活中有一些场景需要延迟或在特定时间发送消息,例如智能热水器需要30分钟后打开,未支付的订单或发送短信、电子邮件和推送通知下午2:00开始的促销活动。RabbitMQ本身没有直接支持延迟...

Java对象拷贝原理剖析及最佳实践(java对象拷贝方法)

作者:宁海翔1前言对象拷贝,是我们在开发过程中,绕不开的过程,既存在于Po、Dto、Do、Vo各个表现层数据的转换,也存在于系统交互如序列化、反序列化。Java对象拷贝分为深拷贝和浅拷贝,目前常用的...

如何将 Qt 3D 渲染与 Qt Quick 2D 元素结合创建太阳系行星元素?

Qt组件推荐:QtitanRibbon:遵循MicrosoftRibbonUIParadigmforQt技术的RibbonUI组件,致力于为Windows、Linux和MacOSX提...

取消回复欢迎 发表评论: