python学习之day6——socket基础

Posted

tags:

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

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

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

socket和file的区别:

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

socket服务端与客户端交流示意图:

技术分享


socket()模块函数

使用socket.socket()函数来创建套接字,语法如下:

socket(socket_family,socket_type,protocol=0)

如前所述,参数一:socket_family(地址簇)

socket.AF_UNIX    只能用于单一的UNIX系统进程间通信

socket.AF_INET     IPV4(默认)

socket.AF_INET6   IPV6 

参数二:socket_type(类型)

socket.SOCK_STREAM 流式socket , for TCP (默认)
socket.SOCK_DGRAM 数据报式socket , for UDP

socket.SOCK_RAW 原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
socket.SOCK_RDM 是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
socket.SOCK_SEQPACKET 可靠的连续数据包服务

参数三:protocol(协议)

0 (默认)与特定的地址家族相关的协议,如果是 0 ,则系统就会根据地址格式和套接类别,自动选择一个合适的协议

创建一个TCP/IP的套接字,你要这样调用socket.socket():

tcpsocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

同样的,创建一个UDP/IP的套接字,你要这样:

udpsocket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

套接字对象(内建)方法:

函数 描述
服务器套接字函数  
s.bind(address) 绑定地址(主机名,端口号对)到套接字
s.listen(backlog) 开始TCP监听
s.accept() 被动接受TCP客户端连接,(阻塞式)等待链接的到来
客户端套接字函数  
s.connect() 主动初始化TCP服务器连接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
公共用途的套接字函数  
s.recv() 接收TCP数据
s.send() 发送TCP数据
s.sendall() 完整发送TCP数据(不停调用s.send())
s.recvfrom() 接收UDP数据
s.sendto() 发送UDP数据
s.getpeername() 链接到当前套接字的远端的地址(TCP连接)
s.getsockname() 当前套接字的地址
s.getsockopt() 返回指定套接字的参数
s.setsockopt() 设置指定套接字的参数
s.close() 关闭套接字
面向模块的套接字函数  
s.setblocking() 设置套接字的阻塞与非阻塞模式
s.settimeout() 设置阻塞套接字操作的超时时间
s.gettimeout() 得到阻塞套接字操作的超时时间
面向文件的套接字函数  
s.fileno() 套接字的文件描述
s.makefile() 创建一个与该套接字相关联的文件对象

例:(win环境)

server端

#!/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(str(client_data,utf8))
    conn.sendall(bytes(不要回答,不要回答,不要回答,utf8))

    conn.close()

client端

#!/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(bytes(请求占领地球,utf8))

server_reply = sk.recv(1024)
print(str(server_reply,utf8))

sk.close()

连续交互通信实例:

 

server端:(win环境)

#!/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(str(client_data,utf8))
    conn.sendall(bytes(不要回答,不要回答,不要回答,utf8))
    while True:
        try:
            client_data = conn.recv(1024)
            print(str(client_data,utf8))
            server_response = input(>>>:).strip()
            
        except Exception:
            print("client closed,break")
            break
        conn.send(bytes(server_response,utf8))
    conn.close()

server端:(Linux环境)

#!/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(str(client_data,utf8))
    conn.sendall(bytes(不要回答,不要回答,不要回答,utf8))
    while True:
        client_data = conn.recv(1024)
        print(str(client_data,utf8))
        server_response = input(>>>:).strip()
if not client_data:break
        conn.send(server_response)

    conn.close()

client端:

#!/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(bytes(请求占领地球,utf8))
server_reply = sk.recv(1024)
print(str(server_reply,utf8))
while True:
    user_input = input(">>>").strip()
    sk.send(bytes(user_input,utf8))
    server_reply = sk.recv(1024)
    print(str(server_reply,utf8))

sk.close()

模拟实现简单ssh功能:

server端:

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

import socket
import subprocess
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()
    while True:
        client_data = conn.recv(1024)
        if not client_data:break
        print("recv cmd:",str(client_data,utf8))
        cmd = str(client_data,utf8).strip()
        cmd_call = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE)
        cmd_result = cmd_call.stdout.read()
        if len(cmd_result) == 0:
            cmd_result = b"cmd execution has no output..."
        ack_msg = bytes("CMD_RESULT_SIZE|%s"%len(cmd_result),"utf8")
        conn.send(ack_msg)
        client_ack = conn.recv(50)
        if client_ack.decode() == "CLIENT_READY_TO_RECV":
            conn.send(cmd_result)

    conn.close()

client端:

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

sk = socket.socket()
sk.connect(ip_port)
while True:
    user_input = input("cmd:").strip()
    if len(user_input) == 0:continue
    if user_input == "q":break
    sk.send(bytes(user_input,utf8))
    #ack_msg = b"CMD_RESULT_SIZE|%s",len(cmd_result)
    server_ack_msg = sk.recv(100)
    cmd_res_msg = str(server_ack_msg.decode()).split("|")
    print("server response:",cmd_res_msg)
    if cmd_res_msg[0] == "CMD_RESULT_SIZE":
        cmd_res_size = int(cmd_res_msg[1])
        sk.send(b"CLIENT_READY_TO_RECV")
    res = ‘‘
    received_size = 0
    while received_size < cmd_res_size:
        data = sk.recv(500)
        received_size += len(data)
        res += str(data.decode())
    else:
        print(str(res))
        print("----------recv doen----------")
sk.close()

以上是关于python学习之day6——socket基础的主要内容,如果未能解决你的问题,请参考以下文章

Python学习之day6 集合

python学习之day6,常用标准模块

Python学习之——Socket套接字(TCP连接)

性能基础知识学习之六---socket接口测试

python学习之day08

python学习之第八天补充