socket
socket编程:
c/s架构--打印机,web服务器osi:一个完整的计算机系统由硬件,操作系统,应用软件组成
学习socket首先需要学互联网协议
cs架构的软件是基于网络来进行通信的
两个服务器机子的通信连接采用光缆,双绞线或者无线电波。
发送的01010101之类的数据需要进行分组才有意义,分组是数据链路层干的。常用以太网
网络层是用ip,如果要传去的地方和原地方不在同一个以太网,就要传去ip然后给网关传去其他的以太网。
192.158.356.1:27015,前面的ip是以太网的标识,网卡号是以太网中某个机器的表示,后面的端口号是
机器上开启的某个应用程序的标识,pid是某个软件的某个进程的标识。

socket封装了tcp/udp协议,是他们的简单的接口,使用socket就遵守了tcp/udp协议
开发效率就高了很多很多。
开发效率就高了很多很多。
套接字:
基于文件的套接字:可以实现一台机器上的两个程序进行通信AF_UNIX
基于网络的套接字:可以实现一台机器上的两个程序进行通信
AF_INET
主要学习AF_INET
套接字工作场景(比喻):
1.买手机2.绑个手机卡
3.开机
4.等电话
5.拿到一个电话链接
6.收发消息
7.断开电话链接
8.关机
简单示例
1.服务端.py的程序
1.服务端.py的程序
import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#第一个参数代表基于网络通信,第二个参数代表基于tcp协议 #以上为买电话 phone.bind(('127.0.0.1',8000)) #以上ip地址和端口,类似插手机卡 phone.listen(5) #5代表最多可以有几个电话呼入,以上类似于电话开机 print('____>') conn,addr=phone.accept() #以上是等电话然后拿到对方的电话链接,前面conn是电话链接,后面的addr是手机号 print('---->') msg=conn.recv(1024) print('客户端发来的消息是',msg) #以上代表最多能收到1024的数据 conn.send(msg.upper()) #注意发送和接收的数据必须是二进制的数据 #以上为发送消息 conn.close() #关闭本次通话 phone.close() #关闭手机
2.客户端.py的程序
import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买电话 phone.connect(('127.0.0.1',8000)) #拨通对方的电话号码 phone.send(bytes('hello',encoding='utf-8')) data=phone.recv(1024) print('收到服务端发来的消息:',data)
tcp协议:
TCP 三次握手就好比两个人在街上隔着50米看见了对方,但是因为雾霾等原因不能100%确认,所以要通过招手的方式相互确定对方是否认识自己。
步骤:
张三首先向李四招手(syn),李四看到张三向自己招手后,向对方点了点头
挤出了一个微笑(ack)。张三看到李四微笑后确认了李四成功辨认出了自己(进入estalished状态)。
但是李四还有点狐疑,向四周看了一看,有没有可能张三是在看别人呢,
他也需要确认一下。所以李四也向张三招了招手(syn),张三看到李四向自己招手
后知道对方是在寻求自己的确认,于是也点了点头挤出了微笑(ack),李四看到
对方的微笑后确认了张三就是在向自己打招呼(进入established状态)。
于是两人加快步伐,走到了一起,相互拥抱。
我们看到这个过程中一共是四个动作,张三招手--李四点头微笑--李四招手--张三点头
微笑。其中李四连续进行了2个动作,先是点头微笑(回复对方),然后再次招手(寻求确认)
,实际上可以将这两个动作合一,招手的同时点头和微笑(syn+ack)。于是四个动作就简化
成了三个动作,张三招手--李四点头微笑并招手--张三点头微笑。这就是三次握手的本质,
中间的一次动作是两个动作的合并。
tcp协议是好人协议,所有发过来的都会进行回应。很容易被黑客利用
TCP断开链接的过程和建立链接的过程比较类似,只不过中间的两部并不总是会合成一
步走,所以它分成了4个动作,张三挥手(fin)——李四伤感地微笑(ack)——李四
挥手(fin)——张三伤感地微笑(ack)。

内外网IP定义
内网IP地址就是私有IP地址,不允许在公网上面传递,只能供内部使用。内网使用了私有地址无法访问internet 会用到NAT-地址转换技术,将内部的私有地址转换为可以
访问internet的外网地址让内部可以上网。外网IP地址就是除了私有地址和被保留的
地址外的所有地址,需要申请才能使用。
ABC三类地址中划分出了三类私有地址:
A类10.0.0.0~10.255.255.255
B类172.16.0.0~172.31.255.255
C类192.168.0.0~192.168.255.255
内网概念
即所说的局域网,比如学校的局域网,局域网内每台计算机的IP地址在本局域网内具有互异性,是不可重复的。但两个局域网内的内网IP可以有相同的。
外网概念
即互联网,局域网通过一台服务器或是一个路由器对外连接的网络,这个IP地址是惟一的。也就是说内网里所有的计算机都是连接到这一个外网IP上,通过这一个
外网IP对外进行交换数据的。也就是说,一个局域网里所有电脑的内网IP是互不相
同的,但共用一个外网IP。(用ipconfig/all查到的IP是你本机的内网IP;在网页上
看到的是你连接互联网所使用的IP,即外网)
127开头的IP主要用于测试 如:127.0.0.1 本机地址,主要用于测试。用汉语表示
,就是“我自己”。在baiWindows系统中,这个地址有一个别名“Localhost”。
寻址这样一个地址,是不能把它发到网络接口的。除非出错,否则在传输介质上永
远不应该出现目的地址为“127.0.0.1”的数据包。
改良款客户端与服务端程序
1.服务端.py的程序from socket import * ip_port=('10.38.237.150',5038) devicenum=5 buffer_size=1024 tcp_serve=socket(AF_INET,SOCK_STREAM)#第一个参数代表基于网络通信,第二个参数代表基于tcp协议 tcp_serve.bind(ip_port) tcp_serve.listen(devicenum) while 1: conn,addr=tcp_serve.accept() print('双向链接时:',conn) print('客户端地址:',addr) while 1: try: msg=conn.recv(buffer_size) print('客户端发来的消息是',msg) if not msg: break #这里用于如果客户端强行断开不断发空就跳出 conn.send(msg.upper()) #注意发送和接收的数据必须是二进制的数据 except Exception: break #用于如果客户端强行断掉不会报错 #以上为发送消息 conn.close() tcp_serve.close()
2.客户端.py的程序
from socket import * ip_port=('10.38.237.150',5038) devicenum=5 buffer_size=1024 tcp_client=socket(AF_INET,SOCK_STREAM)#第一个参数代表基于网络通信,第二个参数代表基于tcp协议 tcp_client.connect(ip_port) target=1 if target==1: while 1: neirong=input('请输入发送内容') if neirong =='': #防止输入为空,导致程序卡死 continue if neirong =='jieshu': target=0 tcp_client.send(bytes(neirong,encoding='utf-8')) print('客户端已经发送消息') data=tcp_client.recv(buffer_size) print('服务端发来的消息是',data.decode('utf-8')) tcp_client.close()
3.使用tcp实现远程控制
服务端程序:from socket import * import subprocess ip_port=('10.38.237.150',5038) devicenum=5 buffer_size=1024 tcp_serve=socket(AF_INET,SOCK_STREAM)#第一个参数代表基于网络通信,第二个参数代表基于tcp协议 tcp_serve.bind(ip_port) tcp_serve.listen(devicenum) while 1: conn,addr=tcp_serve.accept() print('双向链接时:',conn) print('客户端地址:',addr) while 1: try: msg=conn.recv(buffer_size) print('客户端发来的消息是',msg) #msg为发过来的命令 if not msg: break #这里用于如果客户端强行断开不断发空就跳出 res=subprocess.Popen(msg.decode('gbk'),shell=True, #使用cmd执行 # 把命令执行的结果放进管道 stderr=subprocess.PIPE, #出错的放进管道stderr stdout=subprocess.PIPE, #结果输出口stdout stdin=subprocess.PIPE #结果放进管道 ) err=res.stderr.read() #查看有没有出错 if err: cmd_res=err #如果有错就是接收err的内容 else: cmd_res=res.stdout.read()#没错就读取程序在cmd运行的结果 conn.send(cmd_res) #注意发送和接收的数据必须是二进制的数据 except Exception: break #用于如果客户端强行断掉不会报错 #以上为发送消息 conn.close() tcp_serve.close()
客户端程序:
from socket import * ip_port=('10.38.237.150',5038) devicenum=5 buffer_size=1024 tcp_client=socket(AF_INET,SOCK_STREAM)#第一个参数代表基于网络通信,第二个参数代表基于tcp协议 tcp_client.connect(ip_port) while 1: neirong=input('请输入发送内容') if neirong =='': #防止输入为空,导致程序卡死 continue if neirong =='quit': break tcp_client.send(bytes(neirong,encoding='gbk')) print('客户端已经发送消息') data=tcp_client.recv(buffer_size) print('服务端发来的消息是',data.decode('gbk')) tcp_client.close()
4.如果重启服务端的时候显示地址已经被使用,可以加入socke配置,重用ip和端口
tcp_serve=socket(AF_INET,SOCK_STREAM)tcp_serve=setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是这句话加在bind前进行ip端口重用
tcp_serve.bind(ip_port)
基于udp的套接字
1.简单的实现
udp服务端程序from socket import * ip_port=('10.38.237.150',5038) buffsize=1024 udp_server=socket(AF_INET,SOCK_DGRAM) #使用udp套接字 udp_server.bind(ip_port) while 1: data,addr=udp_server.recvfrom(buffsize) print('接收到的数据',data) #可见接收到的是一个元组,元组的第一位是发的数据 #第二位是客户端的ip地址和端口 print('客户端的地址',addr) udp_server.sendto(data.upper(),addr)
udp客户端程序
from socket import * ip_port=('10.38.237.150',5038) buffsize=1024 udp_client=socket(AF_INET,SOCK_DGRAM) #数据报 while 1: neirong=input('请输入内容:') udp_client.sendto(bytes(neirong,encoding='utf8'),ip_port) data,addr=udp_client.recvfrom(buffsize) print(data.decode('utf8'))
2.udp的优势:
udp可以与同时和多个客户端进行沟通。而tcp时间内只能和一个客户端进行沟通,其他那些进来的客户端会被挂
起,等到正在沟通的客户端断联其他的客户端才能进去沟通
3.使用udp实现ntp
udp服务端程序from socket import * import time ip_port=('10.38.237.150',5038) buffsize=1024 udp_server=socket(AF_INET,SOCK_DGRAM) #使用udp套接字 udp_server.bind(ip_port) while 1: data,addr=udp_server.recvfrom(buffsize) print('接收到的数据',data) #可见接收到的是一个元组,元组的第一位是发的数据 #第二位是客户端的ip地址和端口 print('客户端的地址',addr) backtime=time.strftime('%Y-%m-%d-%X') udp_server.sendto(backtime.encode('utf8'),addr)
udp客户端程序
from socket import * ip_port=('10.38.237.150',5038) buffsize=1024 udp_client=socket(AF_INET,SOCK_DGRAM) #数据报 while 1: neirong=input('请输入内容:') udp_client.sendto(bytes(neirong,encoding='utf8'),ip_port) data,addr=udp_client.recvfrom(buffsize) print(data.decode('utf8'))

浙公网安备 33010602011771号