Socket

socket()模块函数用法

import socket
 socket.socket(socket_family,socket_type,protocal=0)
 socket_family 可以是 AF_UNIX(同主机) 或 AF_INET(网络,用这个)。socket_type 可以是 SOCK_STREAM(流式) 或 SOCK_DGRAM(报文)。protocol 一般不填,默认值为 0。
 
 获取tcp/ip套接字
 tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 
 获取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)
服务端套接字函数
s.bind() 绑定(主机,端口号)到套接字
s.listen() 开始TCP监听
s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来

客户端套接字函数
s.connect() 主动初始化TCP服务器连接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常

公共用途的套接字函数
s.recv() 接收TCP数据
s.send() 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
s.recvfrom() 接收UDP数据
s.sendto() 发送UDP数据
s.getpeername() 连接到当前套接字的远端的地址
s.getsockname() 当前套接字的地址
s.getsockopt() 返回指定套接字的参数
s.setsockopt() 设置指定套接字的参数
s.close() 关闭套接字

面向锁的套接字方法
s.setblocking() 设置套接字的阻塞与非阻塞模式
s.settimeout() 设置阻塞套接字操作的超时时间
s.gettimeout() 得到阻塞套接字操作的超时时间

面向文件的套接字的函数
s.fileno() 套接字的文件描述符
s.makefile() 创建一个与该套接字相关的文件

例1:TCP

from socket import *
phone=socket(AF_INET,SOCK_STREAM)  #TCP连接
phone.bind(('127.0.0.1',8081))
phone.listen(5) #最多5个监听

conn,addr=phone.accept() #等待连接进入
while True:
    data=conn.recv(1024)
    print('server===>')
    print(data)
    conn.send(data.upper())
conn.close()
phone.close()
服务端
from socket import *

phone=socket(AF_INET,SOCK_STREAM)
phone.connect(('127.0.0.1',8081))

while True:
    msg=input('>>: ').strip()
    phone.send(msg.encode('utf-8'))
    print('client====>')
    data=phone.recv(1024)
    print(data)
客户端

 

例2:UDP

from socket import *
phone=socket(AF_INET,SOCK_DGRAM)
phone.bind(('127.0.0.1',8082))
while True:
    msg,addr=phone.recvfrom(1024)
    phone.sendto(msg.upper(),addr)
服务端
from socket import *
phone=socket(AF_INET,SOCK_DGRAM)
while True:
    msg=input('>>: ')
    phone.sendto(msg.encode('utf-8'),('127.0.0.1',8082))
    msg,addr=phone.recvfrom(1024)
    print(msg)
客户端

 

tcp服务端:

ss = socket() #创建服务器套接字
ss.bind()      #把地址绑定到套接字
ss.listen()      #监听链接
inf_loop:      #服务器无限循环
    cs = ss.accept() #接受客户端链接
    comm_loop:         #通讯循环
        cs.recv()/cs.send() #对话(接收与发送)
    cs.close()    #关闭客户端套接字
ss.close()        #关闭服务器套接字(可选)

 

tcp客户端:

1 cs = socket()    # 创建客户套接字
2 cs.connect()    # 尝试连接服务器
3 comm_loop:        # 通讯循环
4     cs.send()/cs.recv()    # 对话(发送/接收)
5 cs.close()            # 关闭客户套接字

 

案例:

import socket
ip_port=('127.0.0.1',8081)
BUFSIZE=1024
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # TCP 连接
s.bind(ip_port) #
s.listen(5)     #可以5个等待连接


while True:                         #新增接收链接循环,可以不停的接收
    conn,addr=s.accept()            #等待连接
    print(conn)
    print(addr)
    while True:                         #新增通信循环,可以不断的通信,收发消息
        msg=conn.recv(BUFSIZE)             #听消息,听话

        if len(msg) == 0:break        #如果不加,那么正在链接的客户端突然断开,recv便不再阻塞,死循环发生

        print(msg,type(msg))

        conn.send(msg.upper())          #发消息,说话

    conn.close()                    #挂电话

s.close()                       #手机关机
服务端
import socket
ip_port=('127.0.0.1',8081)
BUFSIZE=1024
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

s.connect_ex(ip_port)           #拨电话

while True:                             #新增通信循环,客户端可以不断发收消息
    msg=input('>>: ').strip()
    if len(msg) == 0:continue
    s.send(msg.encode('utf-8'))         #发消息,说话(只能发送字节类型)

    feedback=s.recv(BUFSIZE)                           #收消息,听话
    print(feedback.decode('utf-8'))

s.close()                                       #挂电话
客户端

 

重用socket接口

重用socket接口,closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket:

#加入一条socket配置,重用ip和端口

phone=socket(AF_INET,SOCK_STREAM)
phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
phone.bind(('127.0.0.1',8080))

 

linux解决大量TIME_WAIT的方法:

发现系统存在大量TIME_WAIT状态的连接,通过调整linux内核参数解决,
vi /etc/sysctl.conf

编辑文件,加入以下内容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
 
然后执行 /sbin/sysctl -p 让参数生效。
 
net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;

net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;

net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。

net.ipv4.tcp_fin_timeout 修改系統默认的 TIMEOUT 时间

socketserver()

基于tcp的socketserver我们自己定义的类中的

  1.   self.server即套接字对象
  2.   self.request即一个链接
  3.   self.client_address即客户端地址

基于udp的socketserver我们自己定义的类中的

  1.   self.request是一个元组(第一个元素是客户端发来的数据,第二部分是服务端的udp套接字对象),如(b'adsf', <socket.socket fd=200, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=('127.0.0.1', 8080)>)
  2.   self.client_address即客户端地址

创建sockeserver的步骤

  1. 必须自己创建一个请求处理类,并且这个类要继承BaseRequestHandlerclass,并且还有重写父类里的handle()
  2. 你必须实例化TCPServer,并且传递server ip和你在第一步创建的请求处理类给这个TCPServer
  3. 接下来调server.handle_request()(只处理一个请求)或者server.serve_forever()(处理多个客户端请求,永远执行)
  4. 调用server_close()去关闭socket

实例:

 1 import socketserver
 2 
 3 
 4 class MyTCPHandler(socketserver.BaseRequestHandler):  # 继承BaseRequestHandler这个基类
 5     def handle(self):
 6         # self.request is the TCP socket connected to the client
 7         while True:
 8             try:
 9                 self.data = self.request.recv(1024)
10                 print("{0} write:".format(self.client_address[0]))
11                 print(self.data)
12                 self.request.send(self.data.upper())
13             except ConnectionResetError as e:  # 抓去异常,这个异常当客户端断开服务端出现断开,这个只有在python3.0才会有
14                 print("error:", e)
15                 break
16 
17 
18 if __name__ == "__main__":
19     HOST, PORT = "localhost", 9999
20     server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)  # 每起一个TCPServer都会实例化MyTCPHandler这个类
21     server.serve_forever()  # 实现多个链接
22     server.server_close()  # 关闭socketserver
服务端
 1 import socket
 2 
 3 client = socket.socket()
 4 client.connect(("localhost", 9999))
 5 
 6 while True:
 7     cmd = input(">>>:").strip()
 8     if len(cmd) == 0: continue
 9     client.send(cmd.encode("utf-8"))
10     cmd_res = client.recv(500)
11     print(cmd_res.decode("utf-8", 'ignore'))
12 
13 client.close()
客户端

 

posted @ 2017-12-14 17:56  大川哥  阅读(188)  评论(0编辑  收藏  举报