文章目录

  • Scoket API
  • Winsock Socket API函数
  • 客户端软件设计
  • LInux下实现TCP/IP通信
    • 服务器端
    • 客户端
  • 网络字节顺序
  • 网络协议栈
  • 参考

  想要开发自己的网络应用的话,使用的比较多的就是Socket编程。应用编程接口API就是应用进程的控制权和操作系统的控制权进行转换的一个系统调用接口。几种典型的应用编程接口有:Berkeley UNIX操作系统定义的一种API,称为套接字接口(socket interface),简称套接字(socket)。在此基础上,微软公司在其操作系统中采用了套接字接口API,形成了一个稍有不同的API,并称之为Windows Socket Interface(WINSOCK)。除此之外,AT&T为其UNIX系统定义了一种API,简写为TLI(Transport Layer Interface)。

Scoket API

  Socket最初是伯克利在国防项目中设计的一个API,最初的套接字API是面向TCP/IP协议栈接口的,目前套接字API是绝大多数工业的标准,绝大多数操作系统都支持。套接字API是网络应用最典型的API接口,支持客户/服务器(C/S)通信模型,在应用层提供了应用进程间通信的一种抽象机制

  但是这里会有一个问题,通常在一个主机上应用层会有很多应用进程,每一个服务器的进程,为了支持客户端与其通信,就必须给出与服务器中的哪一个应用进程进行通信。从传输层的角度来看,服务器端的传输层也需要确定出服务器进程,因此传输层会给每个应用进程一个端口号(16位整数),因此标识一个通信端点,我们就采用IP地址+端口号的方式(对外),操作系统/进程通过套接字描述符(socket descriptor)(对内)管理套接字。

  套接字对内,对外的管理是不一样的,作为套接字,在使用套接字描述符,在管理这些套接字的时候,事实上是一种套接字的抽象机制。这种抽象机制非常类似于我们文件的抽象,也就是说它把套接字看作一个特殊的文件,当应用进程创建套接字时,操作系统分配一个数据结构存储套接字相关信息。这种抽象机制可以利用下图这样一个示意图来表示:

 左侧是套接字描述符的一个表,在windows进程中,每一个进程都会管理这样一个表,当你创建一个套接字,就会在这个表中增加一个入口,每个入口都有一个指针,指向一个套接字的数据结构。这个套接字的数据结构里面存储了这个套接字的相关信息,套接字中非常重要的信息就是地址信息。有时候我们也会将IP地址加端口号称为端点地址。有时候使用套接字的时候,我们就会使用本地的和远端的端点地址来进行通信。在套接字的结构里面已经定义了sockaddr_in这样一个结构包含了IP地址和端口号:

struct sockaddr_in{u_char sin_len; /* 地址长度 */u_char sin_family; /* 地址族(TCP/IP :AF_INET) */u_short sin_port; /* 端口号 */struct in_addr sin_addr; /* IP地址 */char sin_zero[8]; /* 未用(置0) */
}

这里还有一个地址族使得其能够用于非TCP/IP的通信。使用TCP/IP协议族的网络应用程序声明端点地址变量时,使用结构sockaddr_in来声明端点地址变量。

Winsock Socket API函数

  上文主要介绍了套接字socketAPI,接下来我们主要介绍套接字的一些函数(以winsock为例)。winsock对伯克利的socket进行了一些扩展,扩展的函数通常以WSA开头。在winsock函数里面:

  1. 最开始调用的是WSAStartup这个初始化函数,初始化windows socket api
  2. 之后调用应用程序,
  3. 最后调用WSACleanup函数,释放所使用的Windows Sockets DLL

  原因在于winsock的实现机制是以windows的动态连接库这种方式来实现的。最开始调用WSAStartup函数实际上是要初始化动态连接库,最后调用WSACleanup是要释放动态连接库。接下来看一下这几个函数:

- WSAStartup:函数用于初始化socket库,仅对Winsock函数有用;
- WSACleanup:清除/终止socket库的使用(仅对WinSock);
- socket:创建套接字;
- connect:“连接”远端服务器(仅用于客户端);
- closesocket:释放/关闭套接字;
- bind绑定套接字的本地IP地址和端口号(通常客户端不需要);
- listen:是置服务器端TCP套接字为监听模式,并设置队列大小(仅用于服务器端TCP套接字)。
- accept:接受/提取一个连接请求,创建新套接字,通过新套接字(仅用于服务器端的TCP套接字)
- recv:接收数据(用于tcp套接字或连接模式的客户端udp套接字)
- recvfrom:接收数据报(用于非连接模式的UDP套接字)
- send:发送数据,(用于TCP套接字或连接模式的客户端UDP套接字)
- setsockopt:设置套接字选项参数
- getsockopt:获取套接字选项参数
  • WSAStartup函数

  使用Socket的应用程序在使用Socket之前必须首先调用WSAStartup函数:

wVersionRequested = MAKEWORD(2, 1);
err = WSAStartup(wVersionRequested, &wsaData);

  第一个参数指明程序请求使用的WinSock版本,其中高位字节指明副版本,地位字节指明副版本、低位字节指明主版本,例如十六进制整数,例如0x102表示2.1版。第二个参数返回实际的WinSock的版本信息,指向WSADATA结构的指针。

  • WSACleanup函数
int WSACleanup (void);

  应用程序在完成对请求的Socket库的使用,最后要调用WSACleanup函数。解除与Socket库的绑定,释放Socket库所占用的系统资源。

  • scoket函数

  socket函数,用于创建套接字,不管客户端还是服务器端,应用进程要通信,按照套接字api的这样一个机制,它必须要事先创建套接字,创建的方式就是调用socket这个函数,这个函数调用成功以后就会返回一个套接字描述符(sd),后续的在系统环境里面,对这个套接字的所有的访问,都是通过套接字描述符来引用的。socket函数需要三个参数:

sd = socket(protofamily, type, proto)
  1. 第一个参数:协议族,protofamily=PF_INET,最开始是面向TCP/IP协议栈的,后面可以面向其它的协议,而控制面向哪种协议的参数,就是这个协议族protofamily
  2. 第二个参数:套接字类型,是进一步确定面向这个协议族,创建的是哪种类型的套接字。
  3. 第三个参数:协议号,0标识默认协议。

  socket面向TCP/IP可以创建的套接字类型,或者说服务类型:应用进程要通信,要创建套接字,套接字架TCP起了应用层与传输层之间的一个接口,传输层有两个典型的协议TCPUDP。如果创建的套接字是TCP的,那么也称为sock_stream,也称为流式套接字,如果创建的套接字是UDP的,就是数据报套接字sock_dgram。除了对传输层的套接字之外,还可以直接面向网络层创建套接字,网络层的协议主要包括IP协议/ICMP协议/IGMP协议等等,这种套接字为sock_raw,也称为原始套接字,因此操作系统对这类套接字具有特殊的权限。

  • closesocket函数
int closesocket(SOCKET sd);

  关闭一个描述符为sd的套接字,如果多个进程共享一个套接字的时候,调用closesocket将套接字引用计数减1,减至0才关闭。一个进程中的多线程对一个套接字的使用无计数,如果进程中的一个线程调用closesocket将一个套接字关闭,该进程中的其他线程也将不能访问该套接字。如果返回0,则表示调用成功,如果出错,会返回一个socket_error常量。

  • bind函数
int bind(so, localaddr, addrlen)

  操作系统会创建一个数据结构来存储套接字的相关信息,其中很重要的一类信息就是地址信息。套接字最初创建的时候它的地址信息可能没有,这个时候我们可以通过调用bind函数来为套接字设置地址信息,为这个套接字设定本地端点地址信息参数:套接字描述符(sd),端点地址(localaddr)。如果是客户程序,一般不必调用bind函数。

  • listen函数
int listen(sd, queuesize)

  基于套接字的机制下,网络应用程序都是采取客户/服务器(C/S)方式进行通信,作为服务器方套接字,如果期望以服务器身份进行通信的话,就需要把服务器端套接字置为一种被动的监听的一种状态;就是listen函数可以完成的任务。更准确的说listen函数是置服务器端的流套接字处于监听状态,因此listen函数只用于服务器端,并且只用于面向连接的流套接字(TCP套接字)。

  在我们这个函数的调用过程中,同时还为套接字设置了一个缓存队列,用于缓存客户服务请求。这个函数调用成功返回的是0,调用失败返回的是socket_error

  • connect函数
connect(sd, queuesize)

  connect函数只用于客户端,客户程序调用connect函数来使客户端套接字(sd)与特定计算机的特定端口(saddr)的套接字(服务)进行连接。不仅可用于TCP客户端,还可用于UDP客户端。

  客户端调用connect函数的话,就会向服务器端发送一个连接请求,服务器拿到这个连接请求之后,就可以进行进一步的处理。如果是UDP来调用的话(UDP协议是无连接的),它只是指定了服务器的端点地址而已,并不一定能与服务器进行通信。

  • accept函数
newsock = accept(sd, caddr, caddrlen)

  作为服务器端,一个套接字创建成功,绑定了端点地址,指定了一个端口号,并且通过调用listen处于一种被动的监听模式,指定了一个队列大小,这个时候服务器端的TCP套接字就需要调用accept函数。因此accept函数只用于服务器端,只用于TCP套接字。

  服务器程序调用accept函数从处于监听状态的流套接字sd的客户连接请求队列中取出排在最前的一个客户请求,并且创建一个新的套接字来与客户套接字创建连接通道这种做法可以实现并发的TCP服务器

  这也就是操作系统端口只有65535个,为什么能够做到几百万的并发?:服务器端给客户端分配资源的时候,是通过五元组<本地IP,本地Port,远程IP,远程Port,protocol>来确定的。本地的Port只是这五元组中的一个,五元组的组合可以很多,所以可以做到几百万的并发。

  • send函数
send(sd, *buf, len, flags)

  send函数,可用于TCP套接字(因为已经建立了连接,所以可用于客户与服务器)或调用了connect函数的UDP客户端套接字(这里一定要注意没有连接的UDP)。

  • sendto函数
sendto(sd, *buf, len, flags, destaddr, addrlen)

  sendto函数用于无连接模式的UDP套接字,比如说UDP的服务器端套接字,或者是客户端的未调用的UDP套接字。

  • recv和recvfrom

  接收数据常用的两个函数为recv,和recvfrom,与sendsendto非常相似:

  1. recv函数从TCP连接的另一端接收数据,或者从调用了connect函数的UDP客户端套接字接收服务器发送来的数据。
  2. recvfrom函数用于从UDP服务器端套接字与未调用connect函数的UDP客户端套接字接收对端数据。
  • setsockopt和setsockopt

  套接字参数的设置和套接字选项参数的读取。

int setsockopt(int sd, int level, int optname, *optval, int optlen)
int getsockopt(int sd, int level, int optname, *optval, socklen_t *optlen)

  setsockopt()函数用来设置套接字sd的选项参数,getsockopt()函数用于获取任意类型、任意状态套接口的选项。

  • 网络应用的Socket API调用基本流程

  客户服务的网络通信程序中,首先运行的一定是服务器,在winsock环境下,

  1. 首先会调用WSAStartup
  2. 这个函数调用完成之后就需要调用sock函数创建一个服务器端的套接字,服务器端套接字创建成功以后;
  3. 接下来调用bind函数为这个套接字绑定端点地址;
  4. 接下来作为服务器端的TCP套接字,我们需要调用listen,把套接字置为监听模式,并指定一个队列大小;
  5. 再接下来我们就需要调用accept函数,来接收一个客户端的一个连接请求;

  当一个客户端期望与服务器通信的话,在winsock环境下,

  1. 首先调用WSAStartup
  2. 也需要通过socket函数创建一个客户端套接字;
  3. 作为客户端程序,通常不需要调用bind绑定端点地址,因为操作系统可以帮助我们去填写,所以客户端调用connect函数即可;

客户端软件设计

  客户端软件设计的时候有几个问题需要解决:

  1. 用户使用域名或者IP地址来表示期望与之通信的服务器的时候,需要将这样一个IP地址进行转换,将其转化为IP协议需要使用的32位二进制IP地址;这里可以调用函数inet_addr()实现点分十进制IP地址到32IP地址转换,函数gethostbyname()可以实现域名到32IP地址的转换,函数gethostbyname()返回的实际上是一个指向结构hostent的指针。
  2. 客户端还可能使用服务名(如HTTP)标识服务器端口,需要将服务名转换为熟知端口号,这个函数返回的实际上也是一个servent的指针,里面包含了服务名对应的端口号;
  3. 除此之外,协议还可能使用协议号来标识,客户端可能使用协议名(如:TCP)指定协议,此时就需要解析协议号,函数getprotobyname ()能够实现协议名到协议号的转换。
  • TCP客户端软件流程
  1. 确定服务器IP地址与端口号
  2. 创建套接字
  3. 分配本地端点地址(IP地址+端口号)(系统完成)
  4. 连接服务器(套接字)
  5. 遵循应用层协议进行通信
  6. 关闭/释放连接
  • UDP客户端软件流程
  1. 确定服务器IP地址与端口号
  2. 创建套接字
  3. 分配本地端点地址(IP地址+端口号)
  4. 指定服务器端点地址,构造UDP数据报
  5. 遵循应用层协议进行通信
  6. 关闭/释放套接字

LInux下实现TCP/IP通信

  一个socket由两部分组成:1. 文件描述符fd。2. 网络协议栈。

服务器端

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <iostream>
#define PORT 7000
#define QUEUE 20int main() {fd_set rfds;struct timeval tv;int retval, maxfd;     //选择器/*创建socket*/int ss = socket(AF_INET, SOCK_STREAM, 0);   //AF_INET IPV4 ;SOCK_STREAM TCP// 将套接字和IP、端口绑定struct sockaddr_in server_sockaddr;server_sockaddr.sin_family = AF_INET; // 使用IPv4地址server_sockaddr.sin_port = htons(PORT); // 端口server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址/*bind*/if(bind(ss, (struct sockaddr* ) &server_sockaddr, sizeof(server_sockaddr))==-1) {perror("bind");exit(1);}// 进入监听状态,等待用户发起请求if(listen(ss, QUEUE) == -1) {perror("listen");exit(1);}// 接收客户端请求struct sockaddr_in client_addr;socklen_t length = sizeof(client_addr);///成功返回非负描述字,出错返回-1int conn = accept(ss, (struct sockaddr*)&client_addr, &length); //目测需要客户端部分的addrif( conn < 0 ) {perror("connect");exit(1);}while(1) {/*把可读文件描述符的集合清空*/FD_ZERO(&rfds);/*把标准输入的文件描述符加入到集合中*/FD_SET(0, &rfds);maxfd = 0;/*把当前连接的文件描述符加入到集合中*/FD_SET(conn, &rfds);/*找出文件描述符集合中最大的文件描述符*/if(maxfd < conn)maxfd = conn;/*设置超时时间*/tv.tv_sec = 5;tv.tv_usec = 0;/*等待聊天*/retval = select(maxfd+1, &rfds, NULL, NULL, &tv);if(retval == -1){printf("select出错,客户端程序退出\n");break;}else if(retval == 0){printf("服务端没有任何输入信息,并且客户端也没有信息到来,waiting...\n");continue;}else{/*客户端发来了消息*/if(FD_ISSET(conn,&rfds)){char buffer[1024];memset(buffer, 0 ,sizeof(buffer));int len = recv(conn, buffer, sizeof(buffer), 0);if(strcmp(buffer, "exit\n") == 0) break;printf("%s", buffer);//send(conn, buffer, len , 0);把数据回发给客户端}/*用户输入信息了,开始处理信息并发送*/if(FD_ISSET(0, &rfds)){char buf[1024];fgets(buf, sizeof(buf), stdin);//printf("you are send %s", buf);send(conn, buf, sizeof(buf), 0);}}}// 关闭套接字close(conn);close(ss);return 0;
}

客户端

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>#define MYPORT  7000
#define BUFFER_SIZE 1024
int main()
{int sock_cli;fd_set rfds;struct timeval tv;int retval, maxfd;///创建套接字,定义sockfdsock_cli = socket(AF_INET,SOCK_STREAM, 0);///定义sockaddr_instruct sockaddr_in servaddr;memset(&servaddr, 0, sizeof(servaddr)); // 每个字节都用0填充servaddr.sin_family = AF_INET;servaddr.sin_port = htons(MYPORT);  ///服务器端口servaddr.sin_addr.s_addr = inet_addr("202.118.18.xxx");  ///服务器ip//连接服务器,成功返回0,错误返回-1while (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0){perror("connect");exit(1);}while(1){/*把可读文件描述符的集合清空*/FD_ZERO(&rfds);/*把标准输入的文件描述符加入到集合中*/FD_SET(0, &rfds);maxfd = 0;/*把当前连接的文件描述符加入到集合中*/FD_SET(sock_cli, &rfds);/*找出文件描述符集合中最大的文件描述符*/if(maxfd < sock_cli)maxfd = sock_cli;/*设置超时时间*/tv.tv_sec = 5;tv.tv_usec = 0;/*等待聊天*/retval = select(maxfd+1, &rfds, NULL, NULL, &tv);if(retval == -1){printf("select出错,客户端程序退出\n");break;}else if(retval == 0){printf("客户端没有任何输入信息,并且服务器也没有信息到来,waiting...\n");continue;}else{/*服务器发来了消息*/if(FD_ISSET(sock_cli,&rfds)){char recvbuf[BUFFER_SIZE];int len;len = recv(sock_cli, recvbuf, sizeof(recvbuf),0);printf("%s", recvbuf);memset(recvbuf, 0, sizeof(recvbuf));}/*用户输入信息了,开始处理信息并发送*/if(FD_ISSET(0, &rfds)){char sendbuf[BUFFER_SIZE];fgets(sendbuf, sizeof(sendbuf), stdin);send(sock_cli, sendbuf, strlen(sendbuf),0); //发送memset(sendbuf, 0, sizeof(sendbuf));}}}close(sock_cli);return 0;
}
  • 三次握手发生在哪个系统API上呢?

  上述代码中,客户端的API:1. socket;2. connect;3. read/recv;4. close。服务器端API:1. socket;2. bind(绑定本地的IP地址);3. listen;4. accept;5. send/write;6. close。

  客户端第一次握手发生在connect上,多个客户端发起connect请求的话,会在服务器端的syn中。若三次握手完成了,服务器收到客户端的ack的时候,服务器会在syn队列中找到相应的数据将其加入到accept队列中。accept函数唯一的作用就是从accept队列中取出一个节点出来。对于服务器而言,三次握手不是在某一个函数内部发生,但accept队列中有节点的话,就能够被取出

  • read/recv、send/write都有什么关系

  它们都是系统调用,每个socket分为两部分,一部分是fd,另外一部分是协议栈。如果是readwrite的话,它是把socket当作一个文件描述符来操作的。而recvsend是把它当作一个TCP协议栈。调用read的时候,会调用系统里面的do_read(),他会判断这个fd是不是文件,判断出来之后还是会调用recv(),之后的操作就是一样的。

  • 四次挥手是不区分服务器与客户端的。谁先调用close,就先发起四次挥手

网络字节顺序

  TCP/IP定义了标准的独立于具体操作系统的网络字节顺序(表示层需要实现的功能,相当于将数据标准格式化),也就是说,在网络的协议头中,存储的这些二进制整数都用网络字节顺序来进行存储,如果使用本地字节顺序,而本地字节顺序又与网络字节顺序不一致的话就会出错。这样就要求某些socket api函数的参数需要存储为网络字节顺序(如IP地址、端口号等)。

  有一些函数可以实现将本地字节顺序与网络字节顺序转换:

  • htons:本地字节顺序->网络字节顺序(16bits), htonl实现32bit的转换;
  • ntohs:将网络字节顺序->本地字节顺序(16bits), ntohl实现32bit的转换;

网络协议栈

  以UDP为例,浅析网络协议栈中数据结构体。更多理论可以参考以太网数据包TCP、IP、ICMP、UDP、ARP协议头结构详解。UDP数据帧如下图所示:

  • 以太网协议头主要包括:目的地址占6个字节,源地址6个字节,类型2个字节。

  依据上图数据包格式,以太网协议头部可以定义为如下形式:

#define ETH_LENGTH 6
struct ethhdr{unsigned char h_dest[ETH_LENGTH]; // 定义目的地址unsigned char h_src[ETH_LENGTH]; // 定义源地址unsigned short proto; // 定义类型};
  • IP协议

  依据上图数据包格式,以IP协议头部可以定义为如下形式:

struct iphdr{unsigned char version:4; // 版本unsigned char hdrlen:4; // 头长度unsigned char tos; // 服务类型unsigned short tos_len; // IP包有多长unsigned short id; // 标识符unsigned short flag:3; // 标志位unsigned short offset:13; // 片断偏移地址unsigned char ttl; // 生存时间ttl,路由器的跳,默认64跳,每经过一个就需要减去1.unsigned char protocol; // 协议unsigned short check; // 校验和unsigned int sip; // 源ip地址unsigned int dip; // 目的ip地址};

变量名后面加冒号是位域操作的表示方法,也就是说后面加上“:1”的意思是这个成员的大小占所定义类型的1 bit。

  • UDP协议头

struct udphdr{unsigned short sport;unsigned short dport;unsigned short len;unsigned short check;};

  写一个完整的包如下:

struct udppkt{struct ethhdr eh;struct iphdr ip;struct udphdr udp;unsigned char body[0]; // 定义用户数据
};

参考

  • https://blog.csdn.net/weixin_37895339/article/details/72810193
  • https://wlink.blog.csdn.net/article/details/80164050

计算机网络基础系列(五)Socket与TCP/IP编程相关推荐

  1. 计算机网络基础:OSI模型与TCP/IP协议的关系

    数据来源 一.分层模型 1)分层思想(把复杂的事情简单化) 通信需要 --> 定义协议标准 完成每一件事,需要的协议太多,怎么办 ?分层,分工合作 将复杂的流程分解为几个功能相当单一的子流程 - ...

  2. socket与tcp/ip编程

    Socket接口是TCP/IP网络的API ,Socket接口定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序.要学Internet上的TCP/IP网络编程,必须理解Socke ...

  3. 聊聊Socket、TCP/IP、HTTP、FTP及网络编程

    1 这些都是什么 既然是网络传输,涉及几个系统之间的交互,那么首先要考虑的是如何准确的定位到网络上的一台或几台主机,另一个是如何进行可靠高效的数据传输.这里就要使用到TCP/IP协议. 1.1 TCP ...

  4. socket跟TCP/IP 的关系,单台服务器上的并发TCP连接数可以有多少

    常识一:文件句柄限制 在linux下编写网络服务器程序的朋友肯定都知道每一个tcp连接都要占一个文件描述符,一旦这个文件描述符使用完了,新的连接到来返回给我们的错误是"Socket/File ...

  5. 转载 Socket与TCP/IP的关系 转(非常好的一篇文章!)

    要写网络程序就必须用 Socket ,这是程序员都知道的.而且,面试的时候,我们也会问对方会不会 Socket 编程?一般来说,很多人都会说, Socket 编程基本就是 listen , accep ...

  6. 计算机网络:浅谈HTTP与TCP/IP四层模型

    计算机网络:浅谈HTTP与TCP/IP四层模型 其实对于我这样的非科班出身来说,理解算法不是最难的.最难的就是计算机网络这种无法一口吃完的内容.因此专门抽空写点这方面的内容.其实本来只是想写一篇HTT ...

  7. Android基础(四):TCP/IP

    Android基础(四):TCP/IP 前言 其实就个人情感来讲,我并不是很想讲这块,甚至很想把这块直接在下个篇章也就是HTTPS中一笔略过的,但是最后仔细想想过后,还是一声长叹,干吧! 先来谈谈协议 ...

  8. java 套接字 访问tcp_Java 网络编程(五) 使用TCP/IP的套接字(Socket)进行通信

    套接字Socket的引入 为了能够方便地开发网络应用软件,由美国伯克利大学在Unix上推出了一种应用程序访问通信协议的操作系统用调用socket(套接字). socket的出现,使程序员可以很方便地访 ...

  9. 网络基础之计算机网络参考模型(OSI参考模型与TCP/IP协议簇)

    文章目录 前言 一.OSI七层参考模型 1.OSI简介 2.OSI参考模型各层的功能 二.TCP/IP协议簇 1.TCP/IP 2.常用的网络协议 三.数据封装和解封装 1.数据封装过程 2.数据解封 ...

  10. socket、tcp/ip、http三者之间的区别和原理

    网络七层模型 OSI 模型(Open System Interconnection model)是计算机和网络在世界范围内实现互联的标准框架.它将计算机网络体系结构划分为七层,每层都可以提供抽象良好的 ...

最新文章

  1. 经典SQL(sqlServer)
  2. OSI参考模型与TCP/IP协议的比较研究
  3. .net 文件类型 及说明
  4. Elastic Search入门:架构说明及Docker方式体验
  5. Acwing 1082. 数字游戏
  6. matlab晶闸管整流电路,采用Matlab/Simulink对三相桥式全控整流电路的仿真分析
  7. 【CV实战】Ubuntu18.04源码编译安装opencv-3.4.X+测试demo
  8. jquery学习之1.12-给节点添加样式
  9. java--tomcat
  10. windows 内部预览版与迅雷极速版不配合
  11. C语言逐行读取文件内容
  12. eCognition易康导出样本
  13. android系统锁屏锁怎么解决方法,安卓手机忘记锁屏密码解决方法【图文详解】...
  14. 计算机网络一、什么是计算机网络
  15. CDH5安装过程中cloudera.server.cmf.Main: Server failed.
  16. 浙江单招单考计算机类本科学校,浙江单考单招能报考哪些大学
  17. 深度学习从入门到精通——图像分割之DeepLab系列算法
  18. php采集喜马拉雅,喜马拉雅数据 JSSDK API 接入 demo WEB版 标准登录 、免登陆
  19. java抽象方法声明_java抽象类和抽象方法
  20. 云上安全办公,就用华为云桌面

热门文章

  1. [UITableView]简介
  2. ubuntu 12.04 lts搭建android 编译环境
  3. 日本惠普发表14.1型液晶内藏笔记本PC「dv4」系列2种模式
  4. WLAN通信基础——WLAN物理层通信技术
  5. Active Directory Get User's groups using LDAP
  6. python supper()函数
  7. 第 10 章 容器监控 - 080 - Weave Scope 容器地图
  8. Android RxVolley = Volley + RxJava + OkHttp
  9. 米洛个人修炼术:注意这三方面,天天都早起
  10. C# 全局唯一标识符 (GUID)