Python脱产8期 Day31 2019/5/28

socket

1.什么是socket:Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口,它把复杂的TCP/IP协议族隐藏在Socket接口后面。简单来说他就是个模块,接口包含了通讯协议。

2.使用socket的目的:有了socket以后,无需自己编写代码实现三次握手,四次挥手,ARP请求,打包数据等等,socket已经封装好了,只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。(节约时间和成本提高开发效率)

3.注意:需明确:关于网络协议 和socket相关概念,对于所有编程语言都是一致的,区别仅仅是各编程语言的函数名称不同

python中的socket

# 1.导入socket模块
import socket

# 2.创建socket对象 函数定义如下
socket.socket(socket_family, socket_type, protocal=0)
# socket_family 可以是 AF_UNIX 或 AF_INET。
# socket_type 可以是 SOCK_STREAM表示TCP协议 或 SOCK_DGRAM表示UDP协议。
# protocol 一般不填,默认值为 0。

# 2.1获取TCP 套接字
tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 或者 后面的参数都有默认值,可以不写,默认创建的是TCP协议socket
tcpSock = socket.socket()

# 2.2获取udp/ip套接字
udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 由于 socket 模块中有太多的属性。可以使用'from module import *'语句。使用 'from socket import *',把 socket 模块里的所有属性都导入当前命名空间里了,这样能大幅减短代码。
# 例如:tcpSock = socket(AF_INET, SOCK_STREAM)
要明确一点:无论是客户端服务器端都使用的都是socket对象
具体事例:
客户端:
import socket

client = socket.socket()
# 指定服务器的端口和ip 客户端的端口系统自动分配的
client.connect(("127.0.0.1",8989)) #


# 添加循环 用来重复收发数据
while True:
# 收发的顺序 必须很对面相反 否则卡死了
msg = input("输入内容:(q:退出)")
if msg == "q":break
if not msg:continue
client.send(msg.encode("utf-8"))
print("sended!")
data = client.recv(1024)
print(data.decode("utf-8"))

client.close()
服务器:
import socket

# 作为服务器必明确自己的ip和端口号 并且不应该变化
# 参数1指定 socket类型AF_INET 表示网络类型
#参数2指定的传输协议为 SOCK_STREAM表示TCP协议 SOCK_DGRAM UDP协议
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 1.买电话机

# 默认就是网络类型 TCP协议
#server = socket.socket()

# 127.0.0.1这叫回送地址 表示当前电脑本身
# ip一定本机ip 本机可能会有多个IP (无线|有限)
# 注意:需要参数是一个元组 端口就是普通整数
server.bind(("127.0.0.1",1688)) # 2.插入手机卡

# 无论是服务器端还是客户端 都是socket 类型

# 开始监听1688端口 盯着这个端口看以后没有数据过来
server.listen() # 3.手机开始待机

# 接收链接请求
# 第一个是表示客户端的socket 第二个客户端的地址信息
client,addr = server.accept() # 4.接电话
# print(type(client))
# print(addr)


# 5.收发数据
data = client.recv(1024)
print(data)
client.send("copy!".encode("utf-8"))

server.close() # 关机

TCP通讯流程

 重点是要先接受通话请求 才能建立连接进行通话,注意TCP中必须先启动服务器再启动客户端,否则客户端由于无法链接服务器,直接报错!

注意:建立是为了传输数据,二传输数据很多时候并不是一次性就传输完成了,需要多次收发过程,所以需要给代码加上循环如下

客户端:

import socket

client = socket.socket()
# 指定服务器的端口和ip 客户端的端口系统自动分配的
client.connect(("127.0.0.1",8989)) #


# 添加循环 用来重复收发数据
while True:
# 收发的顺序 必须很对面相反 否则卡死了
msg = input("输入内容:")
if not msg:continue
client.send(msg.encode("utf-8"))
print("sended!")
data = client.recv(1024)
print(data.decode("utf-8"))


client.close()
服务器
import socket
server = socket.socket()
server.bind(("127.0.0.1",8989))
server.listen()

while True:
client_socket,client_addr = server.accept()
buffer_size = 1024 #缓冲区  就是一个临时的容器  
# 缓冲区大小 不能随便写 太大会导致内存溢出 太小效率低 在内存能够承受的情况下 大一些

while True:
try:
data = client_socket.recv(1024)
# 在linux中 对方如果强行下线了 服务器不会抛出异常 只会收到空消息
# 得加上判断 如果为空则意味着 对方下线了 应该关闭链接 跳出循环
# windows上正常关闭 也会收到空消息 if 必须要加
if not data:
client_socket.close()
break

print(data.decode("utf-8")) # 解码时必须保证双方同意编码方式
# 转为大写在发回去
client_socket.send(data.upper())
except ConnectionResetError as e:
print("%s %s" % (client_addr[0],client_addr[1]),e)
# 如果对方下线了 那服务器也应该关闭对应的客户端对象
client_socket.close()
break


# 通常服务器不会关闭
# server.close()

常见错误

1.端口占用

# 如果已经开启了服务器  再次运行将会抛出 端口占用异常  把之前开启的服务器关掉即可
"""
有些情况 明明已经关闭了进程 但是 还是端口占用
可能是进程正在后台运行 可以通过端口查出进程 进行关闭
windows下
netstat -ano | findstr 9898
tasklist | findstr 进程id 拿到进程名称
taskkill /f /t /im 进程名称

大招: 重启电脑

2.强行关闭链接

1.当客服端与服务器链接成功后,如果一方没有执行close,而是直接强行终止程序(或是遇到异常被迫终止),都会导致另一方发送问题,在windows下,接收数据的一方在recv函数处将抛出异常

2.错误显示:

ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。

3.注意:

linux下,不会抛出异常会导致接收数据的一方,recv方法不断的收到空消息,造成死循环

要使应用程序能够在不同平台正常工作,那需要分别处理这两个问题

4.解决:

客户端

import socket

client = socket.socket()
# 指定服务器的端口和ip 客户端的端口系统自动分配的
client.connect(("127.0.0.1",8989)) #


# 添加循环 用来重复收发数据
while True:
# 收发的顺序 必须很对面相反 否则卡死了
msg = input("输入内容:(q:退出)")
if msg == "q":break
if not msg:continue
client.send(msg.encode("utf-8"))
print("sended!")
data = client.recv(1024)
print(data.decode("utf-8"))

client.close()

 服务器

import socket
server = socket.socket()
server.bind(("127.0.0.1",8989))
server.listen()

while True:
client_socket,client_addr = server.accept()
buffer_size = 1024 #缓冲区  就是一个临时的容器  
# 缓冲区大小 不能随便写 太大会导致内存溢出 太小效率低 在内存能够承受的情况下 大一些

while True:
try:
data = client_socket.recv(1024)
# 在linux中 对方如果强行下线了 服务器不会抛出异常 只会收到空消息
# 得加上判断 如果为空则意味着 对方下线了 应该关闭链接 跳出循环
if not data:
client_socket.close()
break

print("收到数据:",data.decode("utf-8")) # 解码时必须保证双方同意编码方式
# 转为大写在发回去
client_socket.send(data.upper())
except Error as e:
print("%s %s" % (client_addr[0],client_addr[1]),e)
# 如果对方下线了 那服务器也应该关闭对应的客户端对象
client_socket.close()
break


# 通常服务器不会关闭
# server.close()

 

猜你喜欢

转载自www.cnblogs.com/tfzz/p/10939672.html
今日推荐