一:socket基础:

1.1:Socket基础:

  socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)

  socket和file的区别:

  file模块是针对某个指定文件进行 "打开"<——>"读写"<——>"关闭"

  socket模块是针对 服务器端 和 客户端Socket 进行<——>"打开"<——>"读写<——>"关闭"即是夸主机继续通信的一种方法

  Socket的英文原义是“孔”或“插座”,在操作系统上被称作"套接字",用于描述IP地址和端口,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。Socket正如其英文原意那样,像一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电, 有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就可以得到不同的服务,连接是如何建立的呢?

1.2:以下是非常经典的 三次握手:

1.3:有连接就有断开,下图是经过四个过程的端口步骤:

1.4:socket在web的应用:

import  socket
def main1():
#创建socket对象
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.bind(("localhost",8080)) #监听端口
sock.listen(5) #最大连接数 while True:
#阻塞,直到有请求连接,有请求过来才会继续执行
#connrction代表客户端的socket对象,是和客户端通信的连接线
#assress是客户端的IP地址
print("") #阻塞之前打印的信息
connrction,address = sock.accept() #客户的的socket和地址
buf = connrction.recv(1024) #收到的客户端的信息
print(connrction,"connrction") #打印客户端的socket
print(address,"address") #打印客户的的ip
print(buf,"buf") #打印客户的发送的信息,即打印服务器收到的信息
connrction.send(b"HTTP/1.1 200 OK\r\n\r\n") #发给客户端额版本信息
connrction.send(b"Hello WORD")
#connrction.close() #关闭连接 if __name__ == "__main__":
main1() 执行结果:
1111111111
<socket.socket fd=292, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 4848)> connrction
('127.0.0.1', 4848) address
b'GET / HTTP/1.1\r\nHost: 127.0.0.1:8080\r\nConnection: keep-alive\r\nCache-Control: max-age=0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36\r\nAccept-Encoding: gzip, deflate, sdch\r\nAccept-Language: en-US,en;q=0.8,zh;q=0.6,zh-CN;q=0.4\r\nCookie: csrftoken=SJMnWsucXeD3EMra5EGg26PZBVzTOCil\r\n\r\n' buf
1111111111
<socket.socket fd=296, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 4849)> connrction
('127.0.0.1', 4849) address

socket Web应用

1.5:socket 部分常用内置方法介绍:

服务器端套接字函数:

s.bind("ip",port) #绑定主机IP和端口到套接字

s.listen(num) #开始监听最大为num的连接,这个值不能无限大,因为要在内核中维护连接队列。

s.accept() #(阻塞式)等待连接的到来,是属于被动接受的TCP连接

客户端套接字函数:

s.connect(addr) #连接到adr套接字,即初始化TCP服务器连接

s.connect_exaddr(addr) #connect()函数的升级版,出错的时候返回错误码,而不是抛出异常

公共用途的套接字函数:

s.recv(num): #接受数据

s.send() #发送数据

s.sendall() #发送所有数据

s.recvfrom(): #接受UDP数据

s.sendto(): #发送UDP数据

1.6:一个简单的socket服务端和客户端:

import  socket
obj = socket.socket()
obj.bind(("localhost",8123))
obj.listen(5) while True:
print("wating.......")
conn,addr = obj.accept()
clientdata = conn.recv(1024) #主机通信是每个数据包的大小最多为1024单位为字节
print(str(clientdata,"utf8"))
conn.send(bytes("来自服务端的信息","utf8")) #往缓冲区发,会用自己的算法和缓冲区效验,保证数据按要求发送
#conn.sendall(bytes("xxx","utf8")) #一次性将数据全部发送到缓冲区
conn.close()

socket server

import  socket
obj = socket.socket()
obj.connect(("127.0.0.1",8123))
obj.send(bytes("你在哪?","utf8"))
data = obj.recv(1024)
print(obj,"obj")
print(str(data,"utf8"))

socket client

1.7:基于socket的微型聊天功能,实现客户端发送给服务器的数据能自动返回并在服务器进行输出:

import  socket
ip_port = ("127.0.0.1",8080) #绑定主机端口 sk = socket.socket() #实例化方法
sk.bind(ip_port) #监听绑定的本机端口
sk.listen(5) # while True:
print("server is waiting.....")
conn,addr = sk.accept() #将监听到的客户机地址和IP保存到conn和addr
client_data = conn.recv(1024) #接收到的用户请求的数据
print(str(client_data,"utf8")) #打印用户发送的数据
conn.send(client_data) #发送给用户的数据
while True:
client_data = conn.recv(1024)
print("recv:",str(client_data,"utf8"))
if not client_data:break
conn.send(client_data)
conn.close()

Server

import  socket  #导入模块
ip_port = ("127.0.0.1",8080) #用元组绑定要链接的服务器地址和端口
sk = socket.socket() #实例化方法
sk.connect(ip_port) #将端口传递给链接的方法 while True:
aaa = input(">>:")
sk.sendall(bytes(aaa,"utf8")) #发送的数据,python3需要转换成utf8并使用bytes发送
server_reply = sk.recv(1024) #每次接收数据的大小
print(str(server_reply,"utf8")) #打印接收的数据并转换成utf8和bytes
sk.close()

Client

1.8:基于socket的升级版的聊天机器人,可以判断用户的输入而返回不同的信息;

import  socket
ip_port = ("127.0.0.1",8080) #绑定主机端口 sk = socket.socket() #实例化方法
sk.bind(ip_port) #监听绑定的本机端口
sk.listen(5) # while True:
print("server is waiting.....")
conn,addr = sk.accept() #将监听到的客户机地址和IP保存到conn和addr
Flag = True #标记位,用于以后的跳出当前循环
while Flag: #当Flag等关于True的时候进行循环,反之则不循环
client_data = conn.recv(1024) #连接信息
print(conn.getsockname(),"name") #用户在服务器上返回自己的IP和端口
data = str(client_data,"utf8") #用户提交的数据
print(type(data)) #打印用户提交的数据类型
if data == "exit": #判断用户输入的是不是exit
Flag = False
elif data == "": #假如用户输入的是1
conn.sendall(bytes("你选择的是第一款游戏","utf8")) #返回给用户输入的是第一款游戏
print("客户端的选择是:",str(client_data,"utf8")) #在屏幕输出
elif data == "": #假如用户输入的是2
conn.sendall(bytes("你选择的是第二款游戏","utf8")) #返回给用户输入的是第二款游戏
print("客户端的选择是:",str(client_data,"utf8")) #在屏幕输出
else: #如果输入错误
conn.send(bytes("选择不正确,请重新选择","utf8")) #提示用户重新输入
conn.close() #关闭本会话,但sock还在,只是将本用户的会话关闭

Server

import  socket  #导入模块
ip_port = ("127.0.0.1",8080) #用元组绑定要链接的服务器地址和端口
sk = socket.socket() #实例化方法
sk.connect(ip_port) #将端口传递给链接的方法 while True:
print(sk.getpeername()) #用于在客户端上返回服务器的IP和端口
aaa = input(">>:")
sk.sendall(bytes(aaa,"utf8")) #发送的数据,python3需要转换成utf8并使用bytes发送
server_reply = sk.recv(1024) #每次接收数据的大小
print(str(server_reply,"utf8")) #打印接收的数据并转换成utf8和bytes
sk.close()

Client

 Server端执行结果:

client界面及执行结果:

 1.9:反射的作用:

通过字典打开或关闭服务:

import  sys
class WebServer(object):
def __init__(self,host,port):
self.host = host
self.port = port def start(self):
print("server is starting") def stop(self):
print("server is stoping") def restart(self):
self.stop()
self.start() def test_run(self,name):
print("running...",name,self.host) if __name__ == "__main__":
server = WebServer("lcoalhost",1234)
server2 = WebServer("localhost",8080)
#print(sys.argv[1],"-->") cmd_dic = {
"start":server.start,
"stop":server.stop,
} #定义一个包含启动和停止的字典,server.startbei
if sys.argv[1] in cmd_dic: #假如执行的时候第一个参数在字典里面
cmd_dic[sys.argv[1]]() #执行参数,第一个参数为start则执行server.start
print(sys.argv[1]) #显示传递的第一个参数
print(cmd_dic["start"]) #显示传递了参数后的cmd_dic,是一个未执行的函数 执行结果:
C:\Users\zhang\PycharmProjects\S12-python3>python C:\Users\zhang\PycharmProjects\S12-python3\day7\day7\test\kaifa.py start
server is starting
start
<bound method WebServer.start of <__main__.WebServer object at 0x0000000000DB3128>>

通过字典传递参数

通过反射方法

hasattr:判断是否包含某个信息

getattr:获取信息

import  sys
class WebServer(object):
def __init__(self,host,port):
self.host = host
self.port = port def start(self):
print("server is starting") def stop(self):
print("server is stoping") def restart(self):
self.stop()
self.start() if __name__ == "__main__":
server = WebServer("lcoalhost",1234)
server2 = WebServer("localhost",8080) if hasattr(server,sys.argv[1]):
func = getattr(server,sys.argv[1]) #获取server.start的内存地址
func() #等于server.start(),可以给func()传递参数
print(func)
func2 = getattr(server,sys.argv[1])
func2() 执行结果:
C:\Users\zhang\PycharmProjects\S12-python3>python C:\Users\zhang\PycharmProjects\S12-python3\day7\day7\test\kaifa.py start
server is starting
<bound method WebServer.start of <__main__.WebServer object at 0x0000000000D830B8>>
server is starting 反射之—hasattr

反射之hasattr和getattr

setattr:将类传递给类之外的函数:

import  sys
class WebServer(object):
def __init__(self,host,port):
self.host = host
self.port = port def start(self):
print("server is starting") def stop(self):
print("server is stoping") def restart(self):
self.stop()
self.start() def test_run(self,name):
print("running...",name,self.host,self.port) if __name__ == "__main__":
server = WebServer("lcoalhost",1234)
setattr(server,"run",test_run) #将在上面创建的实例server传递给函数test_run,并将test_run重命名为run
server.run(server,"jack") 执行结果:
C:\Users\zhang\PycharmProjects\S12-python3>python C:\Users\zhang\PycharmProjects\S12-python3\day7\day7\test\kaifa.py start
running... jack lcoalhost 1234 setattr

反射之setattr

delattr:删除类的方法:

import  sys
class WebServer(object):
def __init__(self,host,port):
self.host = host
self.port = port def start(self):
print("server is starting") def stop(self):
print("server is stoping") def restart(self):
self.stop()
self.start() def test_run(self,name):
print("running...",name,self.host,self.port) if __name__ == "__main__":
server = WebServer("lcoalhost",1234)
server2 = WebServer("localhost",8080) server.restart() #重启
delattr(server.host) #删除一个传递的参数,等于self.host
server.restart() #再次重启服务器
delattr(WebServer,'start') #删除类的方法,类的方法无法通过server删除,因为start是类的方法,只能通过类删除其内部的方法
server.restart() 执行结果:
C:\Users\zhang\PycharmProjects\S12-python3>python C:\Users\zhang\PycharmProjects\S12-python3\day7\day7\test\kaifa.py start
server is stoping
server is starting
Traceback (most recent call last):
File "C:\Users\zhang\PycharmProjects\S12-python3\day7\day7\test\kaifa.py", line 45, in <module>
delattr(server.host)
TypeError: delattr expected 2 arguments, got 1 delattr

反射之delattr

2.0 创建一个实验SSL整数的socket:

from socket import  socket,AF_INET,SOCK_STREAM
import ssl
KEYFILE = 'server_key.pem' #私有key
CERTFILE ='server_cert.pem' #公有key,传给客户端的
def echo_server(address):
s = socket(AF_INET,SOCK_STREAM)
s.bind(address)
s.listen(1) s_ssl = ssl.wrap_socket(s,
keyfile=KEYFILE,
certfile=CERTFILE,
server_side=True,
)
while True:
c,a = s_ssl.accept()
print("conn to:",a)
#echo_client(c)
while True:
aa = c.recv(1024)
if aa == b'':
break
print(str(aa,"utf8"))
c.send(aa)
c.close()
print("连接关闭") echo_server(("127.0.0.1",20007))

SSL_Server

from socket import  socket,AF_INET,SOCK_STREAM
import ssl
s = socket(AF_INET,SOCK_STREAM)
print("")
KEYFILE = "server_key.pem" #私有key
CERTFILE = "server_cert.pem" #公有key,传给客户端的 s_ssl = ssl.wrap_socket(s,
cert_reqs=ssl.CERT_REQUIRED,
ca_certs="server_cert.pem")
print("")
s_ssl.connect(("127.0.0.1",20007))
while True:
aaa = input(">>:")
s_ssl.sendall(bytes(aaa,"utf8")) #发送的数据,python3需要转换成utf8并使用bytes发送
server_reply = s_ssl.recv(1024) #收到的服务器的数据,每次接收数据的大小
print(str(server_reply,"utf8")) #打印接收的服务器返回的数据并转换成utf8和str
#s_ssl.recv(1024)
#s_ssl.send(b"hello word ?")
s_ssl.close()

SSL_Client

总结:Scket在写的时候要记住:有发就有收,收发必相等!

二:Socket晋级:

socket 详细介绍图:

socket创建参数详解:

server端:

#创建socket对象
sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#socket.AF_INET #参数一
#socket.SOCK_STREAM #参数二

参数一:地址簇

  socket.AF_INET IPv4(默认)
  socket.AF_INET6 IPv6

  socket.AF_UNIX 只能够用于单一的Unix系统进程间通信

参数二:类型

  socket.SOCK_STREAM  流式socket , for TCP (默认)
  socket.SOCK_DGRAM   数据报式socket , for UDP

  socket.SOCK_RAW 原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
  socket.SOCK_RDM 是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
  socket.SOCK_SEQPACKET 可靠的连续数据包服务

参数三:协议

  0  (默认)与特定的地址家族相关的协议,如果是 0 ,则系统就会根据地址格式和套接类别,自动选择一个合适的协议

在创建socket对象的时候一般使用默认即可:sk = socket.socket()

更多参数:

#sk.bind(address)
  s.bind(address) #将套接字绑定到地址。address地址的格式取决于地址族。在AF_INET下,以元组(host,port)的形式表示地址。 #sk.listen(backlog) #开始监听传入连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量。backlog等于5,表示内核已经接到了连接请求,但服务器还没有调用accept进行处理的连接个数最大为5,这个值不能无限大,因为要在内核中维护连接队列 #sk.setblocking(bool) #是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。 #sk.accept() #接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。接收TCP 客户的连接(阻塞式)等待连接的到来 #sk.connect(address) #连接到address处的套接字。一般,address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。 #sk.connect_ex(address) #同上,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回编码,例如:10061 #sk.close() #关闭套接字 #sk.recv(bufsize[,flag]) #接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。flag提供有关消息的其他信息,通常可以忽略。 #sk.recvfrom(bufsize[.flag]) #与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。 #sk.send(string[,flag]) #将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。即:可能未将指定内容全部发送。 #sk.sendall(string[,flag]) #将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。内部通过递归调用send,将所有内容发送出去。 #sk.sendto(string[,flag],address) #将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。该函数主要用于UDP协议。 #sk.settimeout(timeout) #设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如 client 连接最多等待5s ) #sk.getpeername() #返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。 #sk.getsockname() #返回套接字自己的地址。通常是一个元组(ipaddr,port) #sk.fileno() #套接字的文件描述符

最新文章

  1. OpenCascade B-Spline Basis Function
  2. yii2 codeception程序功能测试
  3. solr
  4. android之RadioGroup
  5. iOS奔溃日志总结
  6. Python爬虫学习笔记——豆瓣登陆(二)
  7. 【如何快速的开发一个完整的 iOS 直播 app】(美颜篇)
  8. linux的getcwd和readlink的区别
  9. 第003篇 深入体验C#项目开发(二)
  10. JAVA必备——13个核心规范
  11. Android开发ListView使用OnScrollListener实现分页加载数据
  12. poi的各种单元格样式以及一些常用的配置
  13. NYOJ 128 前缀表达式的计算
  14. WEB UI 上传URL附件(使用方法备份)
  15. MacOS High Sierra 引起 VirtualBox Vagrant 同步慢
  16. java并发之线程间通信
  17. Java爬虫模拟登录——不给我毛概二的H某大学
  18. Freemarker教程1(基本使用)
  19. 【转】python中的一维卷积conv1d和二维卷积conv2d
  20. Java中Dom解析XML

热门文章

  1. UVA 10312 - Expression Bracketing(数论+Catalan数)
  2. UML初了解
  3. ansible变量
  4. Web开发在线工具
  5. C# 常用参数
  6. Week15(12月19日):授课综述2
  7. commons-logging和slf4j都是日志的接口
  8. poj 2752 Seek the Name, Seek the Fame(KMP需转换下思想)
  9. CocoaPods的安装及设置
  10. iOS/Xcode异常:reason = “The model used to open the store is incompatible with the one used to create the store”