网络协议HTTP、TCP、socket学习

原文链接:https://blog.csdn.net/weixin_43122090/article/details/105462015
原文链接:https://blog.csdn.net/Yansky58685/article/details/98118124
原文链接:https://www.cnblogs.com/thinksasa/archive/2013/02/26/2934206.html

1、计算机网络七层模型
在这里插入图片描述
2、网络协议是什么
在计算机网络要做到井井有条的交换数据,就必须遵守一些事先约定好的规则,比如交换数据的格式、是否需要发送一个应答信息。这些规则被称为网络协议。
3、目前较为流行的网络编程模型是客户机/服务器(C/S)结构即通信双方一方作为服务器等待客户提出请求并予以响应。客户则在需要服务时向服务器提 出申请。服务器一般作为守护进程始终运行,监听网络端口,一旦有客户请求,就会启动一个服务进程来响应该客户,同时自己继续监听服务端口,使后来的客户也 能及时得到服务。

4、TCP三次握手了保持一次网络通信交互正常(客户端发送连接请求。服务器接收请求,并予以响应)
一个设备中的数据发送给其他设备,然后接受另外一个设备反馈的数据。(客户端发送给服务器通信连接请求,并接受到服务端响应),客户端需要通信时,会想服务器发起连接请求,而服务器为了时刻响应通信请求,需要一直在线。一旦获取通信,就可以进行数据交互。

5、什么是TCP/IP和UDP
TCP/IP即传输控制/网络协议,是面向连接的协议,发送数据前要先建立连接(发送方和接收方的成对的两个之间必须建 立连接),TCP提供可靠的服务,也就是说,通过TCP连接传输的数据不会丢失,没有重复,并且按顺序到达

UDP它是属于TCP/IP协议族中的一种。是无连接的协议,发送数据前不需要建立连接,是没有可靠性的协议。因为不需要建立连接所以可以在在网络上以任何可能的路径传输,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。
5.1、TCP与UDP区别:

  1. TCP是面向连接的协议,发送数据前要先建立连接,TCP提供可靠的服务,也就是说,通过TCP连接传输的数据不会丢失,没有重复,并且按顺序到达;
  2. UDP是无连接的协议,发送数据前不需要建立连接,是没有可靠性
  3. TCP通信类似于于要打个电话,接通了,确认身份后,才开始进行通行
  4. UDP通信类似于学校广播,靠着广播播报直接进行通信
  5. TCP只支持点对点通信,UDP支持一对一、一对多、多对一、多对多
  6. TCP是面向字节流的,UDP是面向报文的;
  7. 面向字节流是指发送数据时以字节为单位,一个数据包可以拆分成若干组进行发送,而UDP一个报文只能一次发完。
  8. CP首部开销(20字节)比UDP首部开销(8字节)要大
  9. UDP 的主机不需要维持复杂的连接状态表
    建立连接可以两次握手吗?为什么?
    不可以。
    因为可能会出现已失效的连接请求报文段又传到了服务器端。 > client 发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达 server。本来这是一个早已失效的报文段。但 server 收到此失效的连接请求报文段后,就误认为是 client 再次发出的一个新的连接请求。于是就向 client 发出确认报文段,同意建立连接。假设不采用 “三次握手”,那么只要 server 发出确认,新的连接就建立了。由于现在 client 并没有发出建立连接的请求,因此不会理睬 server 的确认,也不会向 server 发送数据。但 server 却以为新的运输连接已经建立,并一直等待 client 发来数据。这样,server 的很多资源就白白浪费掉了。采用 “三次握手” 的办法可以防止上述现象发生。例如刚才那种情况,client 不会向 server 的确认发出确认。server 由于收不到确认,就知道 client 并没有要求建立连接。
    而且,两次握手无法保证Client正确接收第二次握手的报文(Server无法确认Client是否收到),也无法保证Client和Server之间成功互换初始序列号。
    可以采用四次握手吗?为什么
    这个肯定可以。三次握手都可以保证连接成功了,何况是四次,但是会降低传输的效率。

四次挥手的具体细节
在这里插入图片描述
用现实理解三次握手的具体细节TCP的四次挥手

  1. 四次挥手断开连接是因为要确定数据全部传书完了客户与服务器交谈结束之后,客户要结束此次会话,就会对服务器说:我要关闭连接了(第一 次挥手)
  2. 服务器收到客户的消息后说:好的,你要关闭连接了。(第二次挥手)
  3. 然后服务器确定了没有话要和客户说了,服务器就会对客户说,我要关闭连接了。
  4. (第三次挥 手)客户收到服务器要结束连接的消息后说:已收到你要关闭连接的消息。(第四次挥手),才关闭

socket编程
在这里插入图片描述
先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。
网络中进程之间如何通信?
本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类:

  1. 消息传递(管道、FIFO、消息队列)
  2. 同步(互斥量、条件变量、读写锁、文件和写记录锁、信号量)
  3. 共享内存(匿名的和具名的)
    以上通信都方法是基于Linux内核进行通信,无法实现多机通信。多机通信则是基于网络通信 内容包括Ip地址和端口号、数据协议
    网络字节序与主机字节序
    主机字节序就是我们平常说的大端和小端模式:不同的CPU有不同的字节序类型,这些字节序是指整数在内存中保存的顺序,这个叫做主机序。引用标准的Big-Endian和Little-Endian的定义如下:

a) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。

b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

网络字节序:4个字节的32 bit值以下面的次序传输:首先是0~7bit,其次8~15bit,然后16~23bit,最后是24~31bit。这种传输次序称作大端字节序。由于TCP/IP首部中所有的二进制整数在网络中传输时都要求以这种次序,因此它又称作网络字节序。字节序,顾名思义字节的顺序,就是大于一个字节类型的数据在内存中的存放顺序,一个字节的数据没有顺序的问题了。

所以: 在将一个地址绑定到socket的时候,请先将主机字节序转换成为网络字节序,而不要假定主机字节序跟网络字节序一样使用的是Big-Endian。由于 这个问题曾引发过血案!公司项目代码中由于存在这个问题,导致了很多莫名其妙的问题,所以请谨记对主机字节序不要做任何假定,务必将其转化为网络字节序再 赋给socket。
x86系列CPU都是小端字节序
TCP面向连接 打电话 连接可靠 (无差错、不重复、不丢失且按序到达)
TCP支持一对一
UDP面向对象 发短信 连接不可靠 (最大努力交付) 数据量大 比如视频
UDP支持一对一 一对多 多对多的交互通信

socket 通信

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
//#include <linux/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc,char **argv)
{
	char readbuf[128];
	char msg[128]={0};
	int n_read;
	int mark=0;
	struct sockaddr_in s_addr;
	struct sockaddr_in c_addr;
	memset(&s_addr,0,sizeof(  struct sockaddr_in ));
	memset(&c_addr,0,sizeof(  struct sockaddr_in ));
	int c_fd;
	int s_fd;
	if(argc != 3)
	{
		printf("param is not right");
		exit(-1);
	}       
	//1.socket
	s_fd=socket(AF_INET,SOCK_STREAM,0);
	if(s_fd == -1)
	{
		perror("socket");
		exit(-1);
	}   

	s_addr.sin_family=AF_INET;
	s_addr.sin_port=htons(atoi(argv[2]));
	inet_aton(argv[1],&s_addr.sin_addr);
	//2.bind
	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
	//3.listen
	listen(s_fd,10);

	//4.accept
	int len=sizeof(struct sockaddr_in);
	while(1)
	{
		c_fd=accept(s_fd,(struct sockaddr *)&c_addr,&len);
		if(c_fd == -1)
		{
			perror("accept");
		}
		printf("get connect : %s\n",inet_ntoa(c_addr.sin_addr));
		mark++;
		if(fork() == 0 )
		{   
			//6.write
			if(fork() == 0)
			{  
				while(1)
				{ 
					memset(msg,0,sizeof(msg));
					sprintf(msg,"welcome NO.%d client",mark);
					write(c_fd,msg,strlen(msg));
					sleep(3);
				}
			}
			while(1)
			{
                                memset(readbuf,0,sizeof(readbuf));
				//5.read
				n_read=read(c_fd,readbuf,sizeof(readbuf));    //from c_fd to readbuf
				if(n_read == -1 )
				{
					perror("read");
				}
				else 
				{
					printf("get message number from client :%d\nmessage:%s\n",n_read,readbuf); 

				}
			}
                        break;
		} 
	}
	return 0;

}
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
//#include <linux/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>



int main(int argc ,char ** argv)
{
	char readbuf[128];
	char msg[128]={0};
	int n_read;
	struct sockaddr_in c_addr;
	memset(&c_addr,0,sizeof(  struct sockaddr_in ));

	if(argc != 3)
	{
		printf("param is not right");
		exit(-1);
	}       
	int c_fd;
	//1.socket
	c_fd=socket(AF_INET,SOCK_STREAM,0);
	if(c_fd == -1)
	{
		perror("socket");
		exit(-1);
	}   
	c_addr.sin_family=AF_INET;
	c_addr.sin_port=htons(atoi(argv[2]));
	inet_aton(argv[1],&c_addr.sin_addr);
	//2.connect
	if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in)) == -1 )
	{
		perror("connect");
		exit(-1);
	}
	while(1)
	{ 
		if( fork()==0 )
		{
                       while(1)
                       {
			memset(msg,0,sizeof(msg));
			printf("inputing:");
			gets(msg);
			//3.write
			write(c_fd,msg,strlen(msg));
                       }
		}
		//4.read
               while(1)
             {
		n_read=read(c_fd,readbuf,sizeof(readbuf));    //from s_fd to readbuf
		if(n_read == -1 )
		{
			perror("read");
		}
		else 
		{
			printf("%s\n",readbuf); 
		}
              
                memset(readbuf,0,sizeof(readbuf));
             }
	}

	return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值