Fork me on GitHub

Socket 通信流程和 Python 网络编程基础

 

 Socket相关函数总结:

 

 

 

 

 

 

 

 

Python 网络编程

Python 提供了两个级别访问的网络服务:

  • 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统 Socket 接口的全部方法。
  • 高级别的网络服务模块 SocketServer, 它提供了服务器中心类,可以简化网络服务器的开发。

什么是 Socket?

Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。


socket()函数

Python 中,我们用 socket()函数来创建套接字,语法格式如下:

socket.socket([family[, type[, proto]]])

参数

  • family: 套接字家族可以使 AF_UNIX 或者 AF_INET。
  • type: 套接字类型可以根据是面向连接的还是非连接分为 SOCK_STREAM 或 SOCK_DGRAM
  • protocol: 一般不填默认为 0。

Socket 对象(内建)方法

函数描述
服务器端套接字
s.bind() 绑定地址(host,port)到套接字, 在 AF_INET下,以元组(host,port)的形式表示地址。
s.listen() 开始 TCP 监听。backlog 指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为 1,大部分应用程序设为 5 就可以了。
s.accept() 被动接受TCP客户端连接,(阻塞式)等待连接的到来
客户端套接字
s.connect() 主动初始化TCP服务器连接,。一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
公共用途的套接字函数
s.recv() 接收 TCP 数据,数据以字符串形式返回,bufsize 指定要接收的最大数据量。flag 提供有关消息的其他信息,通常可以忽略。
s.send() 发送 TCP 数据,将 string 中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于 string 的字节大小。
s.sendall() 完整发送 TCP 数据。将 string 中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回 None,失败则抛出异常。
s.recvfrom() 接收 UDP 数据,与 recv() 类似,但返回值是(data,address)。其中 data 是包含接收数据的字符串,address 是发送数据的套接字地址。
s.sendto() 发送 UDP 数据,将数据发送到套接字,address 是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。
s.close() 关闭套接字
s.getpeername() 返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。
s.getsockname() 返回套接字自己的地址。通常是一个元组(ipaddr,port)
s.setsockopt(level,optname,value) 设置给定套接字选项的值。
s.getsockopt(level,optname[.buflen]) 返回套接字选项的值。
s.settimeout(timeout) 设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如connect())
s.gettimeout() 返回当前超时期的值,单位是秒,如果没有设置超时期,则返回None。
s.fileno() 返回套接字的文件描述符。
s.setblocking(flag) 如果flag为0,则将套接字设为非阻塞模式,否则将套接字设为阻塞模式(默认值)。非阻塞模式下,如果调用recv()没有发现任何数据,或send()调用无法立即发送数据,那么将引起socket.error异常。
s.makefile() 创建一个与该套接字相关连的文件

简单实例

服务端

我们使用 socket 模块的 socket 函数来创建一个 socket 对象。socket 对象可以通过调用其他函数来设置一个 socket 服务。

现在我们可以通过调用 bind(hostname, port) 函数来指定服务的 port(端口)

接着,我们调用 socket 对象的 accept 方法。该方法等待客户端的连接,并返回 connection 对象,表示已连接到客户端。connection 其实就是客户端的socket。因为服务器可能同时与多个客户端通信,需要用 connection 区分这些客户端。

完整代码如下:

实例

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import socket
# 建立一个服务端
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(('localhost',6999)) #绑定要监听的端口
server.listen(5) #开始监听 表示可以使用五个链接排队
while True:# conn就是客户端链接过来而在服务端为期生成的一个链接实例
    conn,addr = server.accept() #等待链接,多个链接的时候就会出现问题,其实返回了两个值
    print(conn,addr)
    while True:
        try:
            data = conn.recv(1024)  #接收数据
            print('recive:',data.decode()) #打印接收到的数据
            conn.send(data.upper()) #然后再发送数据
        except ConnectionResetError as e:
            print('关闭了正在占线的链接!')
            break
    conn.close()

  

客户端

接下来我们写一个简单的客户端实例连接到以上创建的服务。端口号为 12345。

socket.connect(hosname, port ) 方法打开一个 TCP 连接到主机为 hostname 端口为 port 的服务商。连接后我们就可以从服务端获取数据,记住,操作完成后需要关闭连接。

完整代码如下:

实例

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import socket# 客户端 发送一个数据,再接收一个数据
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #声明socket类型,同时生成链接对象
client.connect(('localhost',6999)) #建立一个链接,连接到本地的6969端口
while True:
    # addr = client.accept()
    # print '连接地址:', addr
    msg = '欢迎访问!'  #strip默认取出字符串的头尾空格
    client.send(msg.encode('utf-8'))  #发送一条信息 python3 只接收btye流
    data = client.recv(1024) #接收一个信息,并指定接收的大小 为1024字节
    print('recv:',data.decode()) #输出我接收的信息
client.close() #关闭这个链接

  

现在我们打开两个终端,第一个终端执行 server.py 文件:

$ python server.py

第二个终端执行 client.py 文件:

$ python client.py 
欢迎访问!

这时我们再打开第一个终端,就会看到有以下信息输出:

连接地址: ('192.168.0.118', 62461)

Python Internet 模块

以下列出了 Python 网络编程的一些重要模块:

协议功能用处端口号Python 模块
HTTP 网页访问 80 httplib, urllib, xmlrpclib
NNTP 阅读和张贴新闻文章,俗称为"帖子" 119 nntplib
FTP 文件传输 20 ftplib, urllib
SMTP 发送邮件 25 smtplib
POP3 接收邮件 110 poplib
IMAP4 获取邮件 143 imaplib
Telnet 命令行 23 telnetlib
Gopher 信息查找 70 gopherlib, urllib

更多内容可以参阅官网的 Python Socket Library and Modules

原文地址:https://www.runoob.com/python/python-socket.html

 


socketserver类的使用

socket不支持并发。socketserver可以实现并发处理,socketserver是对socket的一个封装。

socketserver 包含4个类型:TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer.前两个用于windows,后两个用于Linux.

创建一个SocketServer分3步:(1)创建一个请求处理类,并继承BaseRequestHandler,且在类中重写BaseRequestHandler的handle(). (2)实例化一个TCPServer,且传递server ip 和第一步所创建的请求处理类给实例化对象。(3)处理多个请求 

server.serve_forver()

handle()函数完成与客户端的所有交互。

基本收发的socketserver实例如下:

socketserver:

 

import socketserver

class MyTCPHandler(socketserver.BaseRequestHandler):  #创建一个继承BaseRequestHandler的请求处理类
    def handle(self):   #重写BaseRequestHandler类中的handle()函数
        while True:
            try:     #抓取异常
                self.data=self.request.recv(1024).strip()
                print("{} wrote:".format(self.client_address[0])) #不懂
                print(self.data)
                self.request.send(self.data.upper())
            except ConnectionResetError as e:
                print("error:",e)
                break
if __name__=="__main__":      
    HOST,PORT="localhost",9999
    server=socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler)   #实例化TCPServer且传递server ip地址,端口和上面所创建的请求处理类  Threading线程实现并发
    server.serve_forever()    #处理多个请求

  


客户端:

 

import socket

client=socket.socket()
client.connect(("localhost",9999))


while True:
    msg=input(">>:").strip()
    if len(msg)==0:continue
    client.send(msg.encode())
    data=client.recv(10240)
    print("接收结果:",data.decode())

client.close()

注:ThreadingTCPServer()可实现多线程。多线程即同时与多个用户交互且互不影响。

ForkingTCPServer()是多进程函数。多进程同多线程道理一样。 但是此函数适用于Linux

原文:https://blog.csdn.net/beifangdefengchuilai/article/details/80084364

 


The SocketServer module simplifies the task of writing network servers.

SocketServer是Python中用于并发处理的模块,功能强大,用法简单,今天来简单介绍一下

SocketServer内有五个重要的类:

 

1.BaseServe:这个类是模块里最基本的类,所有的类源头都来至于这个基类,但是他不是用于实例或使用的

2.TCPServer:这个类用于TCP/ip的socket通讯

3.UDPServer:这个类用于UDP的socket通讯

4.UnixStreamServer 和5.UnixDatagramServer :使用的Unix - domain sockets通讯,并且只能Unix平台使用

 

官方的类导向图:

 

+------------+
| BaseServer |
+------------+
      |
      v
+-----------+        +------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+        +------------------+
      |
      v
+-----------+        +--------------------+
| UDPServer |------->| UnixDatagramServer |
+-----------+        +--------------------+

 

 

使用方法:

Creating a server requires several steps. First, you must create a request handler class by subclassing the BaseRequestHandler class and overriding its handle() method; this method will process incoming requests. Second, you must instantiate one of the server classes, passing it the server’s address and the request handler class. Then call the handle_request() or serve_forever() method of the server object to process one or many requests. Finally, call server_close() to close the socket.

意思是说,使用方法大概分四步:

1.创建自己的sockserver类,但必须继承sockeserver中的BaseRequestHandler 类

2.必须重写里面的handle()方法,并把你自己需要处理的交互方式写入,因为这个方法是用于处理的函数

   而看源码可以看到,BaseRequestHandler 中的handle()没有写任何东西,所以需要你自己去写

3.然后你需要调用handle_request() 或者 serve_forever() 来使程序处理一个或者多个请求

4.使用server_close()关闭Socket服务。

 

简单实例:

 

import SocketServer
 
 
 
class MyTCPHandler(SocketServer.BaseRequestHandler):
 
 
 
 
 
def handle(self):
 
 
 
    self.data = self.request.recv(1024).strip() #接收客户端数据
 
    print "{} wrote:".format(self.client_address[0]) #输出屏幕并格式化
 
    print self.data
 
 
 
    self.request.sendall(self.data.upper())	#将收到的数据变成大写并返回给客户端
 
 
 
if __name__ == "__main__":
 
    HOST, PORT = "localhost", 9999
 
 
 
    server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler) #设置ip 和端口号 并把自定义的类填入
 
 
 
    server.serve_forever() #启动服务

  

简单客户端( client):

 

 
import socket
 
 
 
client = socket.socket()
 
 
 
client.connect(('localhost',9999)) #连接服务器
 
 
 
while True:
 
    msg = input(">>:").strip()
 
if len(msg) == 0 :continue
 
    client.send(msg.encode()) #发送数据
 
 
 
    data = client.recv(1024) #接收数据
 
 
 
    print("返回数据:",data.decode())
 
 
 
 
 
client.close()

  

经测试程序可行,但是有个问题就是,这个程序也只能进行单个用户处理,当多用户连接服务器时,服务器并不会

 

崩溃,但确会挂起,只有等当前连接的客户端断开时,才会按顺序连接第二个客户端。

那怎么样才能实现多客户端的多线程操作呢,需要自己去写个多线程的程序吗,不不不,这个模块已经给我们都写好了一个方法。

 

if __name__ =="__main__":
 
HOST,PORT = "localhost",9999
 
 
 
server = socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler)
 
# socketserver.TCPServer
 
server.serve_forever()

  

其实只需把TCPServer()变成ThreadingTCPServer()就可以实现多并发响应客户端了!

 

原文:https://blog.csdn.net/liu915013849/article/details/78905179

posted @ 2021-01-05 14:01  stardsd  阅读(647)  评论(0编辑  收藏  举报