python_day9_socket

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python_day9_socket相关的知识,希望对你有一定的参考价值。

1、socket 套接字工作流程图

2、收发功能

3、不间断一发一收

4、多客户端连接

5、UDP:收发功能

6、UDP:实现时间功能

7、执行命令


socket 套接字工作流程图

  技术分享图片

先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束


AF_UNIX: 基于文件编程 

    基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信


AF_INET: 基于网络编程 有AF_INET6 ipv6

CS架构


SOCK_STREAM: TCP协议   数据流式通信

SOCK_DGRAM:  UDP协议   数据报式的套接字



## 收发功能 

socket服务端

 import socket
 cat=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
 cat.bind(('192.168.0.12',9090))

 cat.listen(4)
 conn,addr=cat.accept()

 msg=conn.recv(1024)
 conn.close()
 print('接收到的信息: %s'%msg)
 conn.send(msg.upper())
 cat.close()

socket客户端

 import socket
 cat=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
 cat.connect(('192.168.0.12',9090))
 cat.send('xiong'.encode('utf-8'))
 data=cat.recv(1024)
 print('接收到的信息: %s'%data)


#服务端会主动断开 已经传输完客户端数据的连接,将状态改变为TIME_WAIT, 四次挥手之后确定数据已经完全传输完,直接断开并清理状态连接信息


# 收发都是在操作自己的缓存区

# recv 接收的字节, 由recv用户态的应用程序发起

# 回车: 当前 socket 内核态缓存没数据 对端内核态也就没法收到数据,自然也就卡死了


##不间断一发一收

socket服务端

 import socket
 cat=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
 cat.bind(('127.0.0.1',9009))
 cat.listen(5)
 conn,addr=cat.accept()
 while True:
     msg=conn.recv(1024)     #回车: 当前 socket 内核态缓存没数据 对端内核态也就没法收到数据,自然也就卡死了
     print('接收到的信息: %s'%msg.decode('utf-8'))
     if msg == b'q' : break
     inp = input('输入一个值: ')
     conn.send(inp.encode('utf-8'))
     continue
 conn.close()
 cat.close()

socket客户端

 import socket
 cat=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
 cat.connect(('127.0.0.1',9009))
 while True:
     inp = input('输入一个值: ')
     if inp == 'q':
         cat.send(inp.encode('utf-8'))
         break
     cat.send(inp.encode('utf-8'))
     msg = cat.recv(1024)
     print('接收到的信息: %s' % msg.decode('utf-8'))
     continue
 cat.close()


## 多客户端连接

# 1、当客户端与服务端建立连接,每次最大客户端连接数由listen控制,我这里最大是5个连接

# 2、多个客户端与服务端建立连接,每次只能有一个客户端与服务端通信,其它队列都会保持在队列中

# 3、unix有些系统使用try except无法解决客户端conn连接突然中断, 可以使用 if not conn: break 

socket服务端

 import socket
 cat=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
 cat.bind(('192.168.2.192',9009))
 cat.listen(5)
 while True:     # 客户端退出,如果队列中还有连接那么再重新建立连接
     conn,addr=cat.accept()      # 连接一次
     while True:     # 与单个用户建立连接
         try:
             msg=conn.recv(1024)   # 当客户端关掉连接,而服务端连接却没有中断,它就直接报错 ConnectionResetError: [WinError 10054]
         except Exception:
             break
         print('接收到的信息: %s'%msg.decode('utf-8'))
         if msg == b'q' : break
         conn.send(msg.upper())
     conn.close()        # 关闭连接
 cat.close()     # 关闭程序

socket客户端

 import socket
 cat=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
 cat.connect(('192.168.2.192',9009))
 while True:
     inp = input('输入一个值: ')
     if inp == 'q':
         cat.send(inp.encode('utf-8'))
         break
     cat.send(inp.encode('utf-8'))
     msg = cat.recv(1024)
     print('接收到的信息: %s' % msg.decode('utf-8'))
     continue
 cat.close()


UDP:收发功能

1、udp不需要建立accept连接,因为无需三次握手建立一条固定的通道

2、多个客户端同时连接服务端,可同时收发信息

3、udp可以接受空 (直接回车)???


recv在自己这端的缓冲区为空时,阻塞

recvfrom在自己这端的缓冲区为空时,就收一个空

UDP_socket服务端

 import socket

 ip_port=('127.0.0.1',9999)
 udp_sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
 udp_sock.bind(ip_port)

 while True:
     data,addr=udp_sock.recvfrom(1024)
     print(data)
     udp_sock.sendto(data,addr)

UDP_socket客户端

 import socket
 ip_port=('127.0.0.1',9999)
 udp_sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

 while True:
     inp = input('>>: ')
     udp_sock.sendto(inp.encode('utf-8'),ip_port)
     data,addr=udp_sock.recvfrom(1024)
     print(data)


UDP:实现时间功能

  # 1、实现时间功能

  # 2、data传递进来是二进制的格式,在strftime之前需要先将格式转换回来

  # 3、注意格式转换,发送都是encode,接受基本都是recvfrom

# udp_socket_server端

 import socket
 import time
 ip_port=('127.0.0.1',9001)
 udp_sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
 udp_sock.bind(ip_port)

 while True:
     data,addr=udp_sock.recvfrom(1024)
     print(data)
     if not data:
         default_time='%Y-%m-%d %X'
     else:
         default_time=data.decode('utf-8')
     udp_back_time=time.strftime(default_time)
     udp_sock.sendto(udp_back_time.encode('utf-8'),addr)

# udp_socket_client端
 import socket
 udp_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
 ip_port=('127.0.0.1',9001)   #TypeError: sendto() takes 2 or 3 arguments (1 given)  需要带地址
 while True:
     inp=input('>>: ')
     udp_client.sendto(inp.encode('utf-8'),ip_port)
     data,addr=udp_client.recvfrom(1024)
     print('现在时间是: %s'%data.decode('utf-8'))
# 1、先运行服务端
# 2、再运行客户端打印结果如下:
		现在时间是: 18
		>>: %Y
		现在时间是: 2018
		>>: 
		现在时间是: 2018-01-04 20:49:53
		>>:


### 执行命令

# socket TCP服务端

 import socket
 import subprocess

 ip_port=('127.0.0.1',9001)
 ip_connect=5
 buff_size=1024

 command=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
 command.bind(ip_port)
 command.listen(ip_connect)

 while True:
 	# 客户端断开之后保持重连
     data,addr=command.accept()
     print('客户端连接信息: %s' %data)
     while True:
         try:
         	# 接收客户端传递过来的值
             cmd_value=data.recv(buff_size)
         except Exception:
             break
         # 执行传递过来的命令,将结果保存到管道对象中赋值给res  
         res=subprocess.Popen(cmd_value.decode('utf-8'),shell=True,
                              stdout=subprocess.PIPE,
                              stdin=subprocess.PIPE,
                              stderr=subprocess.PIPE)

         # 取出stderr的值,如果是空那么执行stdout,不为空说明报错了
         err=res.stderr.read()
         if err:
             cmd_res=err
         else:
             cmd_res=res.stdout.read()
         if not cmd_res:     # 判断如果是类似 cd .. 的命令,它到subprocess值为空
             cmd_res='命令为空'.encode('gbk')
         data.send(cmd_res)
         continue
     data.close()
 command.close()


# socket_客户端 

 import socket

 ip_port=('127.0.0.1',9001)
 ip_connect=5
 buff_size=1024

 command=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
 command.connect(ip_port)

 while True:
     cmd_inp=input('请输入命令: ').strip()
     if not cmd_inp: command
     if cmd_inp == 'quit': break
     command.send(cmd_inp.encode('utf-8'))
     data=command.recv(buff_size)
     print(data.decode('gbk'))
 command.close()

#  最后在客户端这边输入 dir就能看到结果了#  最后在客户端这边输入 dir就能看到结果了


以上是关于python_day9_socket的主要内容,如果未能解决你的问题,请参考以下文章

python_day12_html

python_day9 多进程socket

python_day9 进程池

铁乐学Python_Day33_网络编程Socket模块1

铁乐学Python_Day34_Socket模块2和黏包现象

python_day12_html