tcp和socket有什么关系,与http又有什么联系?
liebian365 2024-12-31 12:45 18 浏览 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;
}
相关推荐
- 4万多吨豪华游轮遇险 竟是因为这个原因……
-
(观察者网讯)4.7万吨豪华游轮搁浅,竟是因为油量太低?据观察者网此前报道,挪威游轮“维京天空”号上周六(23日)在挪威近海发生引擎故障搁浅。船上载有1300多人,其中28人受伤住院。经过数天的调...
- “菜鸟黑客”必用兵器之“渗透测试篇二”
-
"菜鸟黑客"必用兵器之"渗透测试篇二"上篇文章主要针对伙伴们对"渗透测试"应该如何学习?"渗透测试"的基本流程?本篇文章继续上次的分享,接着介绍一下黑客们常用的渗透测试工具有哪些?以及用实验环境让大家...
- 科幻春晚丨《震动羽翼说“Hello”》两万年星间飞行,探测器对地球的最终告白
-
作者|藤井太洋译者|祝力新【编者按】2021年科幻春晚的最后一篇小说,来自大家喜爱的日本科幻作家藤井太洋。小说将视角放在一颗太空探测器上,延续了他一贯的浪漫风格。...
- 麦子陪你做作业(二):KEGG通路数据库的正确打开姿势
-
作者:麦子KEGG是通路数据库中最庞大的,涵盖基因组网络信息,主要注释基因的功能和调控关系。当我们选到了合适的候选分子,单变量研究也已做完,接着研究机制的时便可使用到它。你需要了解你的分子目前已有哪些...
- 知存科技王绍迪:突破存储墙瓶颈,详解存算一体架构优势
-
智东西(公众号:zhidxcom)编辑|韦世玮智东西6月5日消息,近日,在落幕不久的GTIC2021嵌入式AI创新峰会上,知存科技CEO王绍迪博士以《存算一体AI芯片:AIoT设备的算力新选择》...
- 每日新闻播报(September 14)_每日新闻播报英文
-
AnOscarstatuestandscoveredwithplasticduringpreparationsleadinguptothe87thAcademyAward...
- 香港新巴城巴开放实时到站数据 供科技界研发使用
-
中新网3月22日电据香港《明报》报道,香港特区政府致力推动智慧城市,鼓励公私营机构开放数据,以便科技界研发使用。香港运输署21日与新巴及城巴(两巴)公司签署谅解备忘录,两巴将于2019年第3季度,开...
- 5款不容错过的APP: Red Bull Alert,Flipagram,WifiMapper
-
本周有不少非常出色的app推出,鸵鸟电台做了一个小合集。亮相本周榜单的有WifiMapper's安卓版的app,其中包含了RedBull的一款新型闹钟,还有一款可爱的怪物主题益智游戏。一起来看看我...
- Qt动画效果展示_qt显示图片
-
今天在这篇博文中,主要实践Qt动画,做一个实例来讲解Qt动画使用,其界面如下图所示(由于没有录制为gif动画图片,所以请各位下载查看效果):该程序使用应用程序单窗口,主窗口继承于QMainWindow...
- 如何从0到1设计实现一门自己的脚本语言
-
作者:dong...
- 三年级语文上册 仿写句子 需要的直接下载打印吧
-
描写秋天的好句好段1.秋天来了,山野变成了美丽的图画。苹果露出红红的脸庞,梨树挂起金黄的灯笼,高粱举起了燃烧的火把。大雁在天空一会儿写“人”字,一会儿写“一”字。2.花园里,菊花争奇斗艳,红的似火,粉...
- C++|那些一看就很简洁、优雅、经典的小代码段
-
目录0等概率随机洗牌:1大小写转换2字符串复制...
- 二年级上册语文必考句子仿写,家长打印,孩子照着练
-
二年级上册语文必考句子仿写,家长打印,孩子照着练。具体如下:...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)