18.网络编程之socket

1.socket概念

  也叫做套接字。用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求,说白了就是一个接口

2.用法

  first:实例化对象,构造函数:

    obj = socket(family, type, proto, fileno, fileno)

    family:地址簇,表示使用的协议,即TCP/IPv4的协议

    type:表示TCP​或者UDP

    protocol :协议号,默认为0,一般不填

    fileno:如果指定了fileno,其他参数将被忽略

  second:进行绑定:

    socket.bind(address)​

​    address:IP地址与端口,这里是一个元组

  third:开始监听:

扫描二维码关注公众号,回复: 112361 查看本文章

    socket.listen()

    之前版本listen要添加参数n,参数n表示同一时间可以有n个链接等待与server端通信,一般不用

  fourth:调用套接字函数等待连接

    connection,address = socket.accept()

    调用accept方法时,socket会进入'waiting'(或阻塞)状态。客户请求连接时,方法建立连接并返回服务器。accept方法返回一个含有俩个元素的元组,形如(connection,address)。第一个元素(connection)是新的socket对象,服务器通过它与客户通信;第二个元素(address)是客户的internet地址。

  fifth:处理数据

    服务器和客户通过send和recv方法传输数据。

    服务器调用send,采用字符串形式向客户发送信息,send方法返回已发送的字符个数。

    服务器使用recv方法从客户接受信息。

    调用recv时,必须指定一个整数来控制本次调用所接受的最大数据量。recv方法在接受数据时会进入'blocket'状态,最后返回一个字符串,用它来表示收到的数据。如果发送的量超过recv所允许,数据会被截断。多余的数据将缓冲于接收端。以后调用recv时,多余的数据会从缓冲区删除。

  sixth:关闭套接字

用法案例:

基于TCP协议的socket(TCP是基于链接的,必须先启动服务端,自启动客户端去链接客户端)

server端:

import socket
soc = socket.socket()            # 创建一个soc对象
soc.bind(('127.0.0.1',9789))     # 将地址绑定到套接字
soc.listen()                     # 监听端口
conn,addr = soc.accept()         # 接收客户端口链接
re = conn.recv(1024)             # 接收客户端信息
print(re.decode('utf-8'))      # 接收客户端发送的信息,必须转码成unicode
conn.send('海贼王'.encode('utf-8'))  # 给客户端发送信息,必须是bytes类型
conn.close()
soc.close()

client端:

import socket
me = socket.socket()             # 实例化对象
me.connect(('127.0.0.1',9789))   # 把地址绑定到套接字
me.send('one piece'.encode('utf-8'))  # 给server发送消息
ret = me.recv(1024)              # 设置固定接收字节,防止一次加载过多占内存
print(ret.decode('utf-8'))         # 将server端发来的信息解码
me.close()                         # 关闭端口

易错点:这里客户端和服务端发送消息时,必须注意接收与发送顺序

 计算机回环地址:

  127.0.0.1,默认为本机地址,一般在自己电脑测试使用,它不用再过交换机查询

 tcp协议适用范围:

  适用于文件的上传和下载,以及发送重要文件等。每和一个客户端建立连接,都会在自己的操作系统上占用一个资源

  它同一个时间段只能和一个客户端建立连接

基于UDP协议的socket(UDP是无链接的,先启动哪一端都不会报错)

 用法案例:

server端:

import socket
ser = socket.socket(type=socket.SOCK_DGRAM)
ser.bind(('127.0.0.1', 8888))
mes,addr = ser.recvfrom(1024)
print(mes.decode('utf-8'))
ser.sendto('海贼王'.encode('utf-8'), addr)
ser.close()

client端:

import socket
client = socket.socket(type=socket.SOCK_DGRAM)
addr = ('127.0.0.1', 8888)
client.sendto('onepiece'.encode('utf-8'),addr)
mess,addr = client.recvfrom(1024)
print(mess.decode('utf-8'))
client.close()

  这样写虽然没有什么问题,但是基于需要来回编码以及解码,显得很不pythonic,为了解决这个问题,我们特别为内置的socket类编写一个子类,来解决编码转换的问题

创建类方法:

from socket import *
class Mysocket(socket):
	def __init__(self,coding='utf-8'):
		self.coding = coding
		super().__init__(type=SOCK_DGRAM)

	def mysend(self,mess,addr):
		return self.sendto(mess.encode(self.coding),addr)

	def myrecv(self,num):
		mess,addr = self.recvfrom(num)
		return mess.decode(self.coding),addr  

  创建客户端和接收端

# server端
from my_test import Mysocket  # 从文件路径中导入这个类
ser = Mysocket()
ser.bind(('127.0.0.1', 8888))
mes,addr = ser.myrecv(1024)
print(mes)
ser.mysend('海贼王', addr)
ser.close()


# 用户端
from my_test import Mysocket
client = Mysocket()
addr = ('127.0.0.1', 8888)
client.mysend('onepiece',addr)
mess,addr = client.myrecv(1024)
print(mess)
client.close() 

  在UDP下基于服务端完成客户端的时间同步服务,比如机房中的所有机器每隔一段时间都会请求服务器,来获取一个标准时间

# server端

import time
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
ip_port = ('127.0.0.1',9200)
sk.bind(ip_port)
while True:
    msg,addr = sk.recvfrom(1024)   # 接收的是用户端格式化字符串字节码
    sk.sendto(time.strftime(msg.decode('utf-8')).encode('utf-8'),addr)
sk.close()

# client端

import socket
import time
tb = socket.socket(type=socket.SOCK_DGRAM)
ip_port = ('127.0.0.1',9200)
while True:
    tb.sendto('%Y/%m/%d %H:%M:%S'.encode('utf-8'),ip_port)
    mes,addr = tb.recvfrom(1024)
    print(mes.decode('utf-8'))
    time.sleep(1)
tb.close()

  

 

  

猜你喜欢

转载自www.cnblogs.com/LearningOnline/p/8986086.html
今日推荐