Python_socket

TCP : 可靠传输,不安全,UDP: 安全传输,不可靠

一台机器上有2^16-1=65535个端口(1-1024)保留自己开就1024往上

 socket (套接字):也可以理解为它是一个管道,用于描述IP地址和端口

socket是一种特殊的文件:针对服务器端和客户端来 打开(建立链接),读(发送数据),写(接收数据)关闭的模式来实现信息的交换

一、socket函数

 socket.socket(family,type[, protocol])   默认协议为TCP/IP

# socket.slcketpair([family,type[,proto]]]):

# socket.create_connection(address[,timeout[, source_address]])

参数说明:

1.family指定应用程序使用的通信协议的协议族

family参数
socket.AF_UNIX 只能单一的在Unix系统进行进程通信,一种本地的管道(socket)
socket.AF_INET IPv4 为TCP/IP协议的默认值,服务器之间的网络通信
socket.AF_INET6 IPv6

2.type创建套接字的类型

type参数
socket.SOCK_STREAM  流式socket,用于TCP时选用
socket.SOCK_DGRAM 数据报式socket,用于UDP时选用

socket.SOCK_RAM

原始套接字,普通的套接字无法处理ICMP  , IGMP 等网络报文,而SOCK_RAM可以;其次,SOCK_RAM也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCT套接字选项由用户构造IP头。

socket.SOCK_RDM

是一种可靠的UDP形式,即可保证交付数据但不保证顺序 ,SOCK_RAM用来提供对原始协议的低级访问,在需要某些特殊操作时使用,如发生ICMP报文,SOCK_RAM通常仅限于高级用户或管理员运行的程序使用.

3.protocol指明所要接收的协议类型,通常设置为0,系统就会根据地址格式和套接类别自动选择一个合适的协议

protocol参数

socket.IPPROTO_TAW 

相当于protocol=255,此时socket只能用来发送IP包,而不能接收任何的数据,发送的数据需要自己填充IP包头,并且自己计算校验和

socket.IPPROTO_IP

相当于protocol=0,此时用于接收任何的IP数据包,其中校验和和协议分析由系统完成

二、socket内建方法

服务器端套接字

sk.bind()

将套接字绑定地址,address地址的格式取决于地址簇,在AF_INET下,以(host.port )的形式表示地址

sk.listen(backlog) 

开始监听传入连接,backlog指定在拒绝连接之前,可以挂起的最大连接数量,等待排队的最多排几个,如:backlog等于5,表示内核已经接到了连接要求,但服务器还没有调用accept进行处理的连接个数,这个值不能无限大,因为要在内核中维护连接队列。

sk.accept()

接受TCP客户连接并返回(conn,address),阻塞式等待连接其到来,其中conn是新的套接字对象,可以用来接受和发送数据,address 是客户端的地址。
客户端套接字
s.connect() 主动初始化TCP服务器连接,一般address的格式为元组(hostname,port),如果连接出错,则返回socket.error错误
s.connet_ex() 同上,不过,连接成功是返回0,连接失败是返回错误码,不会抛出异常
公共用途套接字

sk.recv(bufsize[,flag])

接受套接字的数据。数据以字符串的形式返回,bufsize指定最多可接收的数据(一般为8192),flag提供有关消息的其他信息,通常可以忽略
sk.recvform() 与recv()类似,多用于接受UDP数据,返回值为(data,address),其中data是包含接受数据的字符串,address是发送数据的套接字地址
sk.send() 发送套接字数据,将string中的数据发送到连接的套接字,返回值是要发送的字节数量,该数据可能小于string的字节大小
sk.sendall() 完整发送TCP数据,将string中的数据发送到连接的套接字,但返回之前会尝试一次性发送,就是不断的调用send,发送成功返回None,失败则抛出异常
sk.sendto() 发送UDP数据,将数据发送到套接字,address的形式是(ipaddr,port)的元组,指定远程地址,返回值是发送的字节数
sk.close() 关闭套接字
sk.getpeername() 返回连接套接字的远程地址,返回值通常是元组(ipaddr,port)
sk.getsockname() 返回套接字自己的地址,通常是一个元组(ipaddr,port)
sk.setsockopt() 设置给定套接字选项的值
sk.getsockopt() 返回条件字选项的值
sk.settimeout(timeout)  设置套接字操作的超时期,timeout是一个浮点数,单位为秒,值为None表示没有超时期,一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如connect())
sk.gettimeout() 返回当前超时期的值,如果没有设置超时期,则返回为None
sk.fileno() 返回套接字的文件描述符
sk.setblocking(flag) 是否阻塞(默认为True),如果设置False或0(即非堵塞模式),那么accept和recv时一旦无数据,则报错
sk.makefile() 创建一个与该套接字相关联的文件

实例一:你说一句,我说一句

import socket
ip_port = ("127.0.0.1", 1313)

sk = socket.socket()
sk.bind(ip_port)       # 创建端口
sk.listen(5)   # 监听多少个

while True:
    print("等待消息。。")
    conn,addr = sk.accept()         # 生成地址和一个实例线程
    while True:
        try:              # 如果客户端端口,没有消息了,抓取异常,跳出循环
            client_data = conn.recv(1024)   # 接收消息
            print(str(client_data, "utf8"))  
        except Exception:
            print("over")
            break

        server_input = input(">>").strip()   # 发送消息
        conn.sendall(bytes(server_input,"utf8"))
    conn.close()
服务器端
import socket

ip_port = ("127.0.0.1",1313)

sk = socket.socket()      # 实例化
sk.connect(ip_port)       # 连接端口
while True:
    client_data = input(">>").strip()
    sk.sendall(bytes(client_data,"utf8"))   # 发送消息
    server_data = sk.recv(1024)            # 接收消息
    print(str(server_data,"utf8"))
sk.close()
客户端

实例二:在Linux上Python3实现客户端发命令,服务器端把客户端命令实现,并发回客户端

#!/usr/bin/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()              # 把 cmd 的执行结果读出来
        if len(cmd_result) == 0:          # 如果结果为 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() == "yes":
            conn.send(cmd_result)     # 确认后,才向客户端发数据
    conn.close()
服务器端
#!usr/bin/python3
# -*- 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   # 按q可以退出

    sk.send(bytes(user_input,'utf8'))        # 发消息

    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"yes")     # 发回消息确认,解决粘包

    res = ''               # 保存 文件内容
    received_size = 0
  #  (在服务器端和客户端中各有一个缓冲区,在一定的时间内客户端接收数据不够500,也会先进行收数据,其他的就下次再收)
    while received_size < cmd_res_size:         # 如果 文件内容,小于发来的长度
        data = sk.recv(500)                # 每次接收最大长度 为500

        received_size += len(data)         # 累加
        res += str(data.decode())
    else:
        print(str(res))
        print('---------------------')
sk.close()
客户端
客户端:


[root@localhost python_day2018_10_28]# python3 client_1.py 
cmd:df
server response: ['CMD_RESULT_SIZE', '521']
Filesystem              1K-blocks    Used Available Use% Mounted on
/dev/mapper/centos-root  18307072 2056032  16251040  12% /
devtmpfs                   490096       0    490096   0% /dev
tmpfs                      500664       0    500664   0% /dev/shm
tmpfs                      500664    6956    493708   2% /run
tmpfs                      500664       0    500664   0% /sys/fs/cgroup
/dev/sda1                  508588  111880    396708  22% /boot
tmpfs                      100136       0    100136   0% /run/user/0

---------------------
cmd:


服务器端:

[root@localhost python_day2018_10_28]# python3 server.py 
server waiting...
recv cmd: df
result
原文地址:https://www.cnblogs.com/Vera-y/p/9930329.html