哗啦啦Python之路 - Day 9 - socket

1. socket是什么

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

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

socket和file的区别:

  • file模块是针对某个指定文件进行【打开】【读写】【关闭】
  • socket模块是针对 服务器端 和 客户端Socket 进行【打开】【读写】【关闭】


2. TCP/IP = transmission control protocol and internet protocol
    - 主机如何接入互联网以及接入互联网和两台主机通信标准的协议
    - 基于TCP协议的软件:阿帕奇等
    - 物理层 + ethernet报头(链路层) + ip报头(网络层)+ tcp报头(运输层)+ http数据包(应用层)

3. socket介于应用层和传输层之间
    TCP服务器端
    - socket() - 绑定协议 (买手机,收发消息的工具)
    - bind() - 绑定端口 (手机号)
    - listen() - 监听,最多挂起的连接数(开机)
    - accept() - 接受请求 (等待电话)
    - read() - 接受消息 (听话)
    - write() - 发送消息 (回话)
    - read()
    - close() - 服务器端再关
    TCP客户端
    - socket() - 封装协议 (找个手机)
    - connect() - 建立连接 (拨号)
    - write() - 发送消息 (说话)
    - read() - 接受消息(收到答复)
    - close() - 客户端先关
    (注意:基于Python 3.5.2版本的socket只能收发字节)

- 服务器端

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import socket

ip_port = (‘127.0.0.1‘,9999)

sk = socket.socket()
sk.bind(ip_port)
sk.listen(5)

while True:
    print ‘server waiting...‘
    conn,addr = sk.accept()

    client_data = conn.recv(1024)
    print client_data
    conn.sendall(‘不要回答,不要回答,不要回答‘)

    conn.close()

socket server

- 客户端

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
ip_port = (‘127.0.0.1‘,9999)

sk = socket.socket()
sk.connect(ip_port)

sk.sendall(‘请求占领地球‘)

server_reply = sk.recv(1024)
print server_reply

sk.close()

socket client

- 其他参数

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()

  套接字的文件描述符

4. 有阻塞行为的有两个:s.accept()和s.recv()

5. 实现功能,一个客户端断了,但是服务端不要断,能连别的客户端
    - 把accept循环起来

6. 粘包

6. 多线程
    - ThreadingTCPServer

内部调用流程为:

  • 启动服务端程序
  • 执行 TCPServer.__init__ 方法,创建服务端Socket对象并绑定 IP 和 端口
  • 执行 BaseServer.__init__ 方法,将自定义的继承自SocketServer.BaseRequestHandler 的类 MyRequestHandle赋值给 self.RequestHandlerClass
  • 执行 BaseServer.server_forever 方法,While 循环一直监听是否有客户端请求到达 ...
  • 当客户端连接到达服务器
  • 执行 ThreadingMixIn.process_request 方法,创建一个 “线程” 用来处理请求
  • 执行 ThreadingMixIn.process_request_thread 方法
  • 执行 BaseServer.finish_request 方法,执行 self.RequestHandlerClass()  即:执行 自定义 MyRequestHandler 的构造方法(自动调用基类BaseRequestHandler的构造方法,在该构造方法中又会调用 MyRequestHandler的handle方法)

服务器端

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import SocketServer

class MyServer(SocketServer.BaseRequestHandler):

    def handle(self):
        # print self.request,self.client_address,self.server
        conn = self.request
        conn.sendall(‘欢迎致电 10086,请输入1xxx,0转人工服务.‘)
        Flag = True
        while Flag:
            data = conn.recv(1024)
            if data == ‘exit‘:
                Flag = False
            elif data == ‘0‘:
                conn.sendall(‘通过可能会被录音.balabala一大推‘)
            else:
                conn.sendall(‘请重新输入.‘)

if __name__ == ‘__main__‘:
    server = SocketServer.ThreadingTCPServer((‘127.0.0.1‘,8009),MyServer)
    server.serve_forever()

服务端

客户端

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import socket

ip_port = (‘127.0.0.1‘,8009)
sk = socket.socket()
sk.connect(ip_port)
sk.settimeout(5)

while True:
    data = sk.recv(1024)
    print ‘receive:‘,data
    inp = raw_input(‘please input:‘)
    sk.sendall(inp)
    if inp == ‘exit‘:
        break

sk.close()

客户端
时间: 2024-10-07 06:33:16

哗啦啦Python之路 - Day 9 - socket的相关文章

哗啦啦Python之路 - Day 1

金融专业出身的人,产生学Python的想法是源于看到通联网络上分享的量化分析师之路. 矿工一直是我的梦想,然而从,c++什么的上手有点难,仿佛想借把锄头挖矿结果从造锄头开始学.相对而言,简单易读易上手的python自然成了不二之选. 于是开始了我的Python之路. Day 1 第一天,自然是从python下载开始.2.7和3.5应该选哪个呢?唔,貌似选择的时候自然是越高版本越好了~哈哈开玩笑.选择3.5的原因当然是因为2.*日薄西山了嘛~~ 工欲善其事,必先利其器.所以下载pycharm或者p

哗啦啦Python之路 - 线程,进程,协程

1. 线程锁 如果不控制多个线程对同一资源进行访问的话,会对数据造成破坏,使得线程运行的结果不可预期.因此要引进线程锁. 线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁. 互斥锁为资源引入一个状态:锁定/非锁定.某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改:直到该线程释放资源,将 资源的状态变成“非锁定”,其他的线程才能再次锁定该资源.互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性. 未引入锁前: impo

哗啦啦Python之路 - Day 3 - 列表和元组

序列和元组 1. 区别: 序列能修改,元组不行 2. 列表写法: user = ['Fiona', 18] user2 = ['Lala', 19] database = [user, user2] print(database) output: ['Fiona', 18],['Lala', 19] 3. 数据结构:container(容器),可以包含其他对象的任意对象.序列(列表和元组)和映射(比如字典)是两种主要的容器. 4. 索引 (indexing): - 所有元素都是有编号的,从0开始

哗啦啦Python之路 - sqlalchemy/paramiko/堡垒机

I. SQLalchemy联表操作 1. 一对多 class Group(Base): # 一对多的表,组中可能包含多个用户 __tablename__ = 'group' nid = Column(Integer, primary_key=True, autoincrement=True) caption = Column(String(32)) class User(Base): __tablename__ = 'user' uid = Column(Integer, primary_key

哗啦啦Python之路 - Day 6 - 三种基础排序,递归,反射,模块

1. 三种排序方式 - 冒泡排序:两两比较,大的排右边,每次冒出去一个泡 m = [1,2,6,5,4] for i in range(len(m)): for j in range(i): if m[j] > m[j+1]: m[j],m[j+1] = m[j+1],m[j] print(m) - 选择排序 对于一组关键字{K1,K2,…,Kn}, 首先从K1,K2,…,Kn中选择最小值,假如它是 Kz,则将Kz与 K1对换:然后从K2,K3,… ,Kn中选择最小值 Kz,再将Kz与K2对换.

哗啦啦python之路 - Day 2 - 程序控制结构

1. 程序流程图 2. if 结构 if score >= 90: print 'A' elif score >= 80: print 'B' elif score >= 70: print 'C' else: print 'D' 3. while 循环结构 count = 0 while count <5: print 'programming is fun!' count += 1 4. break和continue的用法 5. range使用方法 6. 用range算常数e

哗啦啦Python之路 - Day 8 - 多态,类成员,单例模式,异常处理

1. 多态(多种类型) 多态的体现如下: def func(arg): print(arg) func(1) func("alex") func([11,12,13]) #func可以是任何东西 #但是对于C#,java都不是这样,参数必须要指定类型 多态的缺点:在缺少注释的情况下,不知道arg是什么类型,它有什么用处.比如说如果确定好是个list的话,那就可以append().但是不确定的时候就不知道怎么用了. 2. 面向对象中的类成员 1) 字段 - 静态字段: 代码加载时已经创建

Python之路【第六篇】:socket

Python之路[第六篇]:socket Socket socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. socket起源于Unix,而Unix/Linux基本哲学之一就是"一切皆文件",对于文件用[打开][读写][关闭]模式来操作.socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO.打开.关闭

Python之路【第九篇】:Python基础(26)——socket server

socketserver Python之路[第九篇]:Python基础(25)socket模块是单进程的,只能接受一个客户端的连接和请求,只有当该客户端断开的之后才能再接受来自其他客户端的连接和请求.当然我 们也可以通过python的多线程等模块自己写一个可以同时接收多个客户端连接和请求的socket.但是这完全没有必要,因为python标准库已经为 我们内置了一个多线程的socket模块socketserver,我们直接调用就可以了,完全没有必要重复造轮子. 我们只需简单改造一下之前的sock