计算机网络基础系列(五)Socket与TCP/IP编程
文章目录
- 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函数
上文主要介绍了套接字socket
的API
,接下来我们主要介绍套接字的一些函数(以winsock
为例)。winsock
对伯克利的socket
进行了一些扩展,扩展的函数通常以WSA
开头。在winsock
函数里面:
- 最开始调用的是
WSAStartup
这个初始化函数,初始化windows socket api
, - 之后调用应用程序,
- 最后调用
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)
- 第一个参数:协议族,
protofamily=PF_INET
,最开始是面向TCP/IP
协议栈的,后面可以面向其它的协议,而控制面向哪种协议的参数,就是这个协议族protofamily
。 - 第二个参数:套接字类型,是进一步确定面向这个协议族,创建的是哪种类型的套接字。
- 第三个参数:协议号,
0
标识默认协议。
socket
面向TCP/IP
可以创建的套接字类型,或者说服务类型:应用进程要通信,要创建套接字,套接字架TCP
起了应用层与传输层之间的一个接口,传输层有两个典型的协议TCP
和UDP
。如果创建的套接字是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
,与send
和sendto
非常相似:
recv
函数从TCP
连接的另一端接收数据,或者从调用了connect
函数的UDP
客户端套接字接收服务器发送来的数据。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
环境下,
- 首先会调用
WSAStartup
; - 这个函数调用完成之后就需要调用
sock
函数创建一个服务器端的套接字,服务器端套接字创建成功以后; - 接下来调用
bind
函数为这个套接字绑定端点地址; - 接下来作为服务器端的
TCP
套接字,我们需要调用listen
,把套接字置为监听模式,并指定一个队列大小; - 再接下来我们就需要调用
accept
函数,来接收一个客户端的一个连接请求;
当一个客户端期望与服务器通信的话,在winsock
环境下,
- 首先调用
WSAStartup
; - 也需要通过
socket
函数创建一个客户端套接字; - 作为客户端程序,通常不需要调用
bind
绑定端点地址,因为操作系统可以帮助我们去填写,所以客户端调用connect
函数即可;
客户端软件设计
客户端软件设计的时候有几个问题需要解决:
- 用户使用域名或者
IP
地址来表示期望与之通信的服务器的时候,需要将这样一个IP
地址进行转换,将其转化为IP
协议需要使用的32
位二进制IP
地址;这里可以调用函数inet_addr()
实现点分十进制IP
地址到32
位IP
地址转换,函数gethostbyname()
可以实现域名到32
位IP
地址的转换,函数gethostbyname()
返回的实际上是一个指向结构hostent
的指针。 - 客户端还可能使用服务名(如
HTTP
)标识服务器端口,需要将服务名转换为熟知端口号,这个函数返回的实际上也是一个servent
的指针,里面包含了服务名对应的端口号; - 除此之外,协议还可能使用协议号来标识,客户端可能使用协议名(如:
TCP
)指定协议,此时就需要解析协议号,函数getprotobyname ()
能够实现协议名到协议号的转换。
- TCP客户端软件流程
- 确定服务器
IP
地址与端口号 - 创建套接字
- 分配本地端点地址(
IP
地址+端口号)(系统完成) - 连接服务器(套接字)
- 遵循应用层协议进行通信
- 关闭/释放连接
- UDP客户端软件流程
- 确定服务器
IP
地址与端口号 - 创建套接字
- 分配本地端点地址(
IP
地址+端口号) - 指定服务器端点地址,构造UDP数据报
- 遵循应用层协议进行通信
- 关闭/释放套接字
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
,另外一部分是协议栈。如果是read
和write
的话,它是把socket
当作一个文件描述符来操作的。而recv
和send
是把它当作一个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编程相关推荐
- 计算机网络基础:OSI模型与TCP/IP协议的关系
数据来源 一.分层模型 1)分层思想(把复杂的事情简单化) 通信需要 --> 定义协议标准 完成每一件事,需要的协议太多,怎么办 ?分层,分工合作 将复杂的流程分解为几个功能相当单一的子流程 - ...
- socket与tcp/ip编程
Socket接口是TCP/IP网络的API ,Socket接口定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序.要学Internet上的TCP/IP网络编程,必须理解Socke ...
- 聊聊Socket、TCP/IP、HTTP、FTP及网络编程
1 这些都是什么 既然是网络传输,涉及几个系统之间的交互,那么首先要考虑的是如何准确的定位到网络上的一台或几台主机,另一个是如何进行可靠高效的数据传输.这里就要使用到TCP/IP协议. 1.1 TCP ...
- socket跟TCP/IP 的关系,单台服务器上的并发TCP连接数可以有多少
常识一:文件句柄限制 在linux下编写网络服务器程序的朋友肯定都知道每一个tcp连接都要占一个文件描述符,一旦这个文件描述符使用完了,新的连接到来返回给我们的错误是"Socket/File ...
- 转载 Socket与TCP/IP的关系 转(非常好的一篇文章!)
要写网络程序就必须用 Socket ,这是程序员都知道的.而且,面试的时候,我们也会问对方会不会 Socket 编程?一般来说,很多人都会说, Socket 编程基本就是 listen , accep ...
- 计算机网络:浅谈HTTP与TCP/IP四层模型
计算机网络:浅谈HTTP与TCP/IP四层模型 其实对于我这样的非科班出身来说,理解算法不是最难的.最难的就是计算机网络这种无法一口吃完的内容.因此专门抽空写点这方面的内容.其实本来只是想写一篇HTT ...
- Android基础(四):TCP/IP
Android基础(四):TCP/IP 前言 其实就个人情感来讲,我并不是很想讲这块,甚至很想把这块直接在下个篇章也就是HTTPS中一笔略过的,但是最后仔细想想过后,还是一声长叹,干吧! 先来谈谈协议 ...
- java 套接字 访问tcp_Java 网络编程(五) 使用TCP/IP的套接字(Socket)进行通信
套接字Socket的引入 为了能够方便地开发网络应用软件,由美国伯克利大学在Unix上推出了一种应用程序访问通信协议的操作系统用调用socket(套接字). socket的出现,使程序员可以很方便地访 ...
- 网络基础之计算机网络参考模型(OSI参考模型与TCP/IP协议簇)
文章目录 前言 一.OSI七层参考模型 1.OSI简介 2.OSI参考模型各层的功能 二.TCP/IP协议簇 1.TCP/IP 2.常用的网络协议 三.数据封装和解封装 1.数据封装过程 2.数据解封 ...
- socket、tcp/ip、http三者之间的区别和原理
网络七层模型 OSI 模型(Open System Interconnection model)是计算机和网络在世界范围内实现互联的标准框架.它将计算机网络体系结构划分为七层,每层都可以提供抽象良好的 ...
最新文章
- 经典SQL(sqlServer)
- OSI参考模型与TCP/IP协议的比较研究
- .net 文件类型 及说明
- Elastic Search入门:架构说明及Docker方式体验
- Acwing 1082. 数字游戏
- matlab晶闸管整流电路,采用Matlab/Simulink对三相桥式全控整流电路的仿真分析
- 【CV实战】Ubuntu18.04源码编译安装opencv-3.4.X+测试demo
- jquery学习之1.12-给节点添加样式
- java--tomcat
- windows 内部预览版与迅雷极速版不配合
- C语言逐行读取文件内容
- eCognition易康导出样本
- android系统锁屏锁怎么解决方法,安卓手机忘记锁屏密码解决方法【图文详解】...
- 计算机网络一、什么是计算机网络
- CDH5安装过程中cloudera.server.cmf.Main: Server failed.
- 浙江单招单考计算机类本科学校,浙江单考单招能报考哪些大学
- 深度学习从入门到精通——图像分割之DeepLab系列算法
- php采集喜马拉雅,喜马拉雅数据 JSSDK API 接入 demo WEB版 标准登录 、免登陆
- java抽象方法声明_java抽象类和抽象方法
- 云上安全办公,就用华为云桌面
热门文章
- [UITableView]简介
- ubuntu 12.04 lts搭建android 编译环境
- 日本惠普发表14.1型液晶内藏笔记本PC「dv4」系列2种模式
- WLAN通信基础——WLAN物理层通信技术
- Active Directory Get User's groups using LDAP
- python supper()函数
- 第 10 章 容器监控 - 080 - Weave Scope 容器地图
- Android RxVolley = Volley + RxJava + OkHttp
- 米洛个人修炼术:注意这三方面,天天都早起
- C# 全局唯一标识符 (GUID)