什么是C/S架构?python
C/S架构客户端、服务端架构,C/S端软件主要有网络游戏,QQ等
互联网协议是什么?分别介绍五层协议中每一层的功能?算法
互联网协议:计算机之间的通讯标准
物理层:主要是基于电器特性发送高低电压(电信号),高电压对应数字1,低电压对应数字0。原始比特流在物理介质上的传输。
数据链路层:定义电信号的分组方式,两台主机经过MAC地址进行通讯。
网络层:引入IP地址区分不一样的广播/子网,选择正确的路由找到目标主机。
传输层:创建端口到端口的通讯,TCP,UDP。
应用层:供操做系统或应用进行网络通讯的标准接口(FTP,HTTP,TELNET)
基于tcp协议通讯,为什么创建连接须要三次握手,而断开连接却须要四次挥手shell
由于当Server端收到Client端的SYN链接请求报文后,能够直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。可是关闭链接时,当Server端收到FIN报文时,极可能并不会当即关闭SOCKET,因此只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端全部的报文都发送完了,我才能发送FIN报文,所以不能一块儿发送。故须要四次挥手.
为什么基于tcp协议的通讯比基于udp协议的通讯更可靠?编程
TCP协议的通讯是面向链接的协议,只要不获得确认,就从新发送数据报,直到获得对方的确认为止。
UDP协议的通讯它是面向非链接的协议,它不与对方创建链接,而是直接就把数据包发送过去。
流式协议指的是什么协议,数据报协议指的是什么协议?json
流式协议指TCP
数据报协议指UDP
什么是socket?简述基于tcp协议的套接字通讯流程windows
socket是应用层与TCP/IP协议通讯的中间软件抽象层,它是一组接口。它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来讲,一组简单的接口就是所有,让Socket去组织数据,以符合指定的协议。
因此,咱们无需深刻理解tcp/udp协议,socket已经为咱们封装好了,咱们只须要遵循socket的规定去编程,写出的程序天然就是遵循tcp/udp标准的。
什么是粘包? socket 中形成粘包的缘由是什么? 哪些状况会发生粘包现象?服务器
TCP协议是面向流的协议,客户端把多个数据包合并在一块儿发送到服务端,就产生了粘包。
因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所形成的。
只有TCP有粘包现象,UDP永远不会粘包
客户端粘包:
发送端须要等缓冲区满才发送出去,形成粘包(发送数据时间间隔很短,数据量很小,TCP优化算法会当作一个包发出去,产生粘包)
服务端粘包:
接收方不及时接收缓冲区的包,形成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候仍是从缓冲区拿上次遗留的数据,产生粘包)
server.py import socket IP_PORT = ('127.0.0.1', 9999) sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock_server.bind(IP_PORT) sock_server.listen(5) print("start ……") while True: conn, addr = sock_server.accept() # 阻塞直到有链接为止 print('connect by ', addr) while True: try: data = conn.recv(1024) # 收到数据 if not data: break print('server 收到的数据 ', data.decode()) response = input(" input server msg >>> ").strip() conn.send(response.encode()) print("send to data:", response) except ConnectionResetError: # 适用于windows操做系统,防止客户端断开链接后死循环 break conn.close() sock_server.close() ----------------------------------------------------------------------- client.py import socket client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) IP_PORT = ('127.0.0.1', 9999) client_sock.connect(IP_PORT) while True: msg = input(" input client msg >>> ").strip() if not msg: continue client_sock.send(msg.encode()) # 发送用户输入的数据,必须是bytes模式 recv_data = client_sock.recv(1024) print('client recvive data ', recv_data.decode()) # 收到服务器的响应后
9. 基于tcp socket,开发简单的远程命令执行程序,容许用户执行命令,并返回结果网络
server: import socket import subprocess import struct import json def cmd_exec(cmd): """ 执行shell命令 :param cmd: :return: """ p = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() if p.returncode != 0: return stderr return stdout IP_PORT = ('127.0.0.1', 9999) sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock_server.bind(IP_PORT) sock_server.listen(5) print("start ……") while True: conn, addr = sock_server.accept() # 阻塞直到有链接为止 print('connect by ', addr) while True: try: data = conn.recv(1024) # 收到数据 if not data: break print('客户端的命令', data.decode('GBK')) res = cmd_exec(data.decode('GBK')) # 执行cmd命令 # 构造消息头,命令+结果长度,防止粘包 header = { 'cmd': data.decode('GBK'), 'res_size': len(res) } header_json = json.dumps(header) header_bytes = header_json.encode('utf-8') header = struct.pack('i', len(header_bytes)) # 第二步:把报头长度发送给客户端 conn.send(header) # 第三步:把报头内容发送给客户端 conn.send(header_bytes) # 第四步:再发送真实的数据 conn.sendall(res) except ConnectionResetError: # 适用于windows操做系统,防止客户端断开链接后死循环 break conn.close() sock_server.close() -------------------------------------- client: import socket import struct import json client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) IP_PORT = ('127.0.0.1', 9999) client_sock.connect(IP_PORT) while True: msg = input(" input client msg >>> ").strip() if not msg: continue client_sock.send(msg.encode('GBK')) # 发送数据 # 第一步:先收报头 header = client_sock.recv(4) # 第二步:从报头中解析(header数据的长度) header_size = struct.unpack('i', header)[0] print('收到报头长度=', header_size) # 第三步:收到报头解析出对真实数据的描述信息 header_json = client_sock.recv(header_size) header_dict = json.loads(header_json) print('收到报头内容=', header_dict) total_size = header_dict['res_size'] # 第三步:接收真实的数据 recv_size = 0 recv_data = b'' while recv_size < total_size: data = client_sock.recv(1024) recv_data += data recv_size += len(data) print('接收数据 =', recv_data.decode('gbk', 'ignore')) # 若是设置为ignore,则会忽略非法字符; client_sock.close()
架构
11. 基于udp协议编写程序,实现功能socket
执行指定的命令,让客户端能够查看服务端的时间
执行指定的命令,让客户端能够与服务的的时间同步
server: from socket import * import time import struct import json server = socket(AF_INET, SOCK_DGRAM) server.bind(('127.0.0.1', 8880)) while True: print("waiting for message ……") # 收到报头长度 action_type, client = server.recvfrom(1024) print('recv {}'.format(action_type.decode())) if not action_type: print('connect is lost ……') break if action_type: print('start sent to server time ……') server_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) time.sleep(1) server.sendto(server_time.encode('utf-8'), client) server.close() -------------------------------------------------------- client: from socket import * import time import json import struct def send_msg(client, action_type, **kwargs): """ 打包消息,发送到服务器 :param action_type: :param kwargs: :return: """ # 发送cmd print('发送auth报头内容:{}'.format(action_type)) client.sendto(action_type.encode("utf-8"), ('127.0.0.1',8880)) if __name__ == '__main__': client = socket(AF_INET, SOCK_DGRAM) while True: cmd = input("input cmd >> ").strip() if not cmd: continue send_msg(client, cmd) data, server = client.recvfrom(1024) if cmd =='gettime': print("server time is", data.decode()) print("local clock is", time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())) elif cmd == 'synctime': print("server time is {} start sync client clock ……".format(data.decode())) print("local clock is", data.decode()) elif cmd == 'bye': break else: print('input cmd error') client.close()