网络编程

Socket介绍

Socket套接字
Python中提供socket.py标准库,非常底层的接口库
Socket是一种通用的网络编程接口,和网络层次没有一一对应的关系
协议族
AF表示Address Family,用于socket()第一个参数。

名称含义
AF_INETIPV4
AF_INET6IPV6
AF_UNIXUnix Domain Socket ,windows没有

Socket类型

名称含义
SOCK_STREAM面向连接的流套接字。默认值,TCP协议
SOCK_DGRAM无连接的数据报文套接字。UDP协议

TCP编程

Socket编程,需要两端,一般来说需要一个服务端、一个客户端
,服务端成为Server,客户端成为Clent。这种编程被成为CS编程。
TCP服务端编程
服务器端编程步骤

  • 创建Socket对象
  • 绑定ip地址Address和端口Port。bind()方法,IPV4地址为一个二元组(‘ip地址字符串’,Port)
  • 开始监听,将在指定的IP的端口上监听,listen()方法
  • 获取用于传送数据的Socket.accept()–>(socket object , address info),accept方法阻塞等待客户端建立连接,返回一个新的Socket对象和客户端地址的二元组,地址是远程客户端的地址,IPV4中它是一个二元组(clientaddr,port)
  • 接受数据,recv(bufsize[,flags])使用缓冲区接受数据
  • 发送数据,send(bytes)发送数据
    在这里插入图片描述
import socket
sock=socket.socket()
ip='127.0.0.1'
port=9999
#绑定IPV4的地址是一个二元组
sock.bind((ip,port))
#先监听后获取
sock.listen()
sock.accept()
newsock,clientinfo=sock.accept()
print(sock)
print(newsock)
print(clientinfo)

在这里插入图片描述

import socket
import time
server=socket.socket()
ip='127.0.0.1'
port=9999
server.bind((ip,port))

server.listen()
print(server)

newsock,clientinfo=server.accept()

data=newsock.recv(1024)
print(data)
newsock.send('ok good'.encode())

在这里插入图片描述
查看监听端口

#windows命令
netstat -anp tcp | findstr 9999
# linux命令
# netstat -tanl |grep 9999
# ss -tanl | grep 9999
import logging
import socket
import threading
import datetime

FORMAT="%(asctime)s %(threadName)s %(thread)s %(message)s "
logging.basicConfig(format=FORMAT,level=logging.INFO)

class Chat:
    def __init__(self,ip='127.0.0.1',port=9999):
        self.sock=socket.socket()
        self.addr=(ip,port)
        self.client={}
    def start(self):
        self.sock.bind(self.addr)
        self.sock.listen()
        threading.Thread(target=self.accept,name="accept").start()
    def accept(self):
        while True:
            newsock,clientinfo=self.sock.accept()
            self.client[clientinfo]=newsock
            threading.Thread(target=self.recv,args=(newsock,clientinfo)).start()
    def recv(self,newsock:socket.socket,clientinfo):
        while True:
            data=newsock.recv(1024)
            print(data)
            mid="{}{}{}{}".format(data.decode(), newsock, *clientinfo)
            logging.info(mid.encode())
            for i in self.client.values():
                i.send(mid.encode())
    def stop(self):
        for i in self.client.values():
            i.close()
        self.sock.close()
chat=Chat()
chat.start()
b'11111111\r\n'
2019-06-13 11:01:42,726 Thread-1 12436 b"11111111\r\n<socket.socket fd=592, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9999), raddr=('127.0.0.1', 52902)>127.0.0.152902" 

注意:
由于GIL和内置数据结构的读写原子性,单独操作字典的某一项item是安全的,但是便利过程是线程不安全,遍历中有可能会被打断,其他线程如果对字典元素进行增加、弹出,都会影响字典的size,就会抛出异常。

import logging
import socket
import threading
import datetime

FORMAT="%(asctime)s %(threadName)s %(thread)s %(message)s "
logging.basicConfig(format=FORMAT,level=logging.INFO)

class Chat:
    def __init__(self,ip='127.0.0.1',port=9999):
        self.sock=socket.socket()
        self.addr=(ip,port)
        self.client={}
        self.event=threading.Event()
        self.lock=threading.Lock()
    def start(self):
        self.sock.bind(self.addr)
        self.sock.listen()
        threading.Thread(target=self.accept,name="accept").start()
    def accept(self):
        while not self.event.is_set():
            newsock,clientinfo=self.sock.accept()
            with self.lock:
                 self.client[clientinfo]=newsock
            threading.Thread(target=self.recv,args=(newsock,clientinfo)).start()
    def recv(self,newsock:socket.socket,clientinfo):
        while not self.event.is_set():
            data=newsock.recv(1024)
            print(data)
            if data==b'quit' or data==b" ":
                with self.lock:
                    self.client.pop(clientinfo)
                newsock.close()
                break
            mid="{}{}{}{}".format(data.decode(), newsock, *clientinfo)
            logging.info(mid.encode())
            with self.lock:
                for i in self.client.values():
                    i.send(mid.encode())
    def stop(self):
        self.event.set()
        with self.lock:
            for i in self.client.values():
                i.close()
        self.sock.close()
chat=Chat()
chat.start()
while True:
    cmd=input(">>>>>").strip()
    if cmd=="quit":
        chat.stop()
        break
    print(threading.enumerate())

在这里插入图片描述
socket常用方法

名称含义
socket.recv(bufsize[,flags])获取数据,默认是阻塞的方式
socket.recvfrom(bufsize[,flags])获取数据,返回二元组
socket,recv_into(buff[,nbytes[,flags]])获取到nbytes的数据后,存储到buffer中。如果nbytes没有指定或0,将buffer大小的数据存入buffer中,返回接受的字节数
socket.recvfrom_into(buffer[,nbytes[,flags]])获取数据,返回一个二元组(bytes,address)中
socker.send(bytes[,flags])TCP发送数据
socket,sendall(bytes[flags])TCP发送全部数据,成功返回None
socket.sendto(string[flag],address)UDP发送数据
socket.sendfile(file,offset=0,coun=None)发送一个文件直到OFF,使用高性能的os.sendfile机制,返回发送的字节数,如果win下不支持sendfile,或者不是普通文件,使用send()发送文件,offset告诉起始位置
名称含义
socket.getpeername()返回连接套接字的远程地址,返回值通常是元组(ipaddr,port)
socket.getsockname()返回套接字自己的地址,通常是一个元组(ipaddr,port)

MakeFile

sock.makefile( mode="r", buffering=None, *,
                 encoding=None, errors=None, newline=None)

创建一个与该套接字相关联的文件对象,将recv方法看做读方法,将send方法看做写方法

import socket
server=socket.socket()
server.bind(('127.0.0.1',9999))
server.listen()
print('~~~~~~~~~~`')
s,_=server.accept()
f=s.makefile(mode='rw')

line=f.read(10)
print(line)
f.write(line)
f.flush()

f.close()
print(f.closed,s._closed)
s.close()
print(f.closed,s._closed)

server.close()

在这里插入图片描述

TCP客户端编程

  • 创建Socket对象
  • 连接到远端服务端的ip和port,connect()方法
  • 传输数据:使用send、recv方法发送、接受数据
  • 关闭连接释放资源
import socket
import threading
class ChatClient:
    def __init__(self,ip='172.22.141.176',port=9999):
        self.sock=socket.socket()
        self.ipaddr=ip,port
    def start(self):
        self.sock.connect(self.ipaddr)
        threading.Thread(target=self.recv).start()
        threading.Thread(target=slice)
    def send(self):
        msg=input(">>>").encode()
        self.sock.send(msg)
    def recv(self):
        while True:
            self.send()
            data=self.sock.recv(1024)
            print(data)
chat=ChatClient()
chat.start()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值