python网络编程Socket

python网络编程Socket


  -班级:自动化5班
  -姓名:刘廷威 
  -学号:3118001021
  -邮箱:52642202@qq.com

参考资料:《Python核心编程(第三版)》

学习内容:

  • 套接字相关知识(前导)
  • socket模块中的函数、属性和套接字对象内置的方法、属性
  • socket实现TCP服务器/客户端的数据传输
  • socket实现UDP服务器/客户端的数据传输

一、套接字

(一)介绍和分类

  套接字(Socket)是计算机网络数据结构,体现了“通信端点”的概念。在任何类型的通信开始前,网络应用程序都必须创建套接字。
  套接字最初是为主机上两个进程通信而创建。
  套接字的类型有两种:基于文件和面向网络。

(1)基于文件的套接字
    UNIX套接字是套接字里的一个家族,并且有“家族名字”:AF_UNIX(又名AF_LOCAL)。其中AF代表地址家族(Address Family),除了地址家族外还有域家族(Domain Family)和协议家族(Protocol Family)。

    基于文件的套接字用于两个进程运行在同一台计算机上的通信。意味着文件系统支持它们的底层结构,这是因为文件系统是一个运行在同一主机的多个进程之间的共享常量。

(2)基于网络的套接字
    其家族名字为AF_INET,另一个地址家族AF_INET6用于因特网协议(IPv6)寻址。

除此之外还有AF_NETLINK家族(无连接);
AF_TIPC家族:支持透明的进程间通信(TIPC)协议,TIPC允许计算机集群之中的机器相互通信,而无须使用基于IP的寻址方式。

总的来说,Python只支持AF_UNIX、AF_NETLINK、AF_TIPC、AF_INET家族,而网络编程重点讨论AF_INET。

(二)套接字地址:主机-端口对

   1、简单来说,一个套接字就像一个电话插孔,那么主机名和端口号则像区号和电话号码的组合,在拨打电话前必须有其他人在另一端监听。
   2、一个网络地址由主机名和端口号对组成。
   3、计算机有效端口范围0~65535(小于1024的端口预留给了系统)

(三)面向连接的套接字和无连接的套接字

无论采用哪种地址家族,都有两种不同风格的套接字连接方式。

(一)面向连接的套接字
    1、这意味着在进行通信之前必须先建立一个连接。
    2、这种面向连接的通信提供了序列化的、可靠的、不重复的数据交付,并且没有记录边界(指数据包的分割没有固定边界大小)
    3、实现这种连接类型的主要协议是传输控制协议(TCP)。为创建TCP套接字,必须使用SOCK_STREAM(基于流的套接字的其中一种表示)作为套接字类型。
    4、在监听到连接并且成功连接后,会以新的Socket来进行下面的数据传输(就像总接线员会将电话转接给合适的人来处理)。

【注意】由于AF_INET这种套接字使用因特网协议(IP)来搜寻网络中的主机,所以整个系统通常结合这两种协议(TCP/IP)。
    当然,也可以使用TCP和本地套接字(非网络的AF_LOCAL/AF_UNIX)结合,这里很明显并不需要IP。
    

(二)无连接的套接字
    1、意味着通信开始前并不需要建立连接。
    2、意味着数据传输过程中无法保证它的顺序性、可靠性、重复性。
    3、这种类型的套接字指的是数据报类型的套接字。然而,数据报确实保存了记录边界,但也意味着消息是以整体发送的,并非首先分成多个片段。
    4、实现这种连接类型的主要协议是用户数据报协议(UDP)。为创建UDP套接字,必须使用SOCK_DGRAM(datagram数据报)作为套接字类型。

二、Socket模块

(一)socket模块中的函数socket()

    import socket

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

socket(socket_family,socket_type,protocol=0)
---参数:  socket_family指地址家族,如AF_INET、AF_UNIX等等
        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)
【补充】     1、该socket()函数将返回一个套接字对象
             2、因为有很多socket模块属性和方法,所以也可以考虑使用from socket import *这种方式导入。

(二)套接字对象(内置)方法
在利用完socket()函数创建并返回一个套接字对象后,就可以使用socket模块中用于套接字对象的方法和属性,常见的如下:

名称 描述
服务器套接字方法
s.bind(ADDR) 将地址(主机名、端口对)绑定到套接字上。通常地址参数ADDR是以(host,port)形式的元组
s.listen(backlog) 设置并启动TCP监听。bakclog参数至少为1,用于指定在拒绝连接前,操作系统可以挂起的最大连接数量,通常设为5
s.accept() 被动接受TCP客户端连接,(阻塞式地)等待连接到来。当连接成功后返回(NewSock,ADDR),其中NewSock为连接成功后新的套接字,用以接下来的数据传输。ADDR为客户端的地址参数
客户端套接字方法
s.connect(ADDR) 向TCP服务端发起连接。通常地址参数ADDR是以(host,port)形式地元组
s.connect_ex(ADDR) connet()的扩展版本,此时会以错误码的形式返回,而不是抛出一个异常
普通的套接字方法
s.recv(bufsize[,flag]) 接受TCP消息,数据以字符串形式返回。bufsize指定要接收的最大数据,单位为B。flag提供消息有关的信息,通常忽略
s.recv_into() 接收TCP消息到指定的缓冲区
s.send(string) 发送TCP消息,将string中的数据发送到连接的套接字中。返回值是要发送的字节数量。
s.sendall(string) 接收UDP消息,与TCP的recv()类似。但返回值是(data,ADDR),其中data指接受到的字符串数据,ADDR是发送方的套接字地址
s.recvfrom_into(bufsize[,flag]) 接收UDP消息到指定的缓冲区
s.sendto(string[,flag],ADDR) 发送UDP消息。ADDR为远程地址(host,port)。返回值为发送的字节数
s.getpeername() 返回连接套接字(TCP)的远程地址,为(host,port)
s.getsockname() 返回套接字自己的地址(host,port)
s.getsockopt() 返回给定套接字选项的值
s.setsockopt() 设定给定套接字选项的值。默认的socket选项不够用时,使用setsockopt来调整
s.shutdown() 关闭连接
s.close() 关闭套接字
s.detach() 在未关闭文件描述符的情况下关闭套接字,返回文件描述符
s.ioctl() 控制套接字的模式(仅支持Windows)
面向阻塞的套接字方法
s.setblocking(flag) 设置套接字的阻塞或非阻塞模式。flag默认值为1,若为0,则是将套接字设为非阻塞模式
s.settimeout(timeout) 设置阻塞套接字操作的超时时间。timeout为浮点数,单位为秒,值为None时表示没有超时时间
s.gettimeout() 获取阻塞套接字操作的超时时间
面向文件的套接字方法
s.fileno() 返回套接字的文件描述符
s.makefile() 创建与套接字关联的文件对象
数据属性
s.family 返回套接字家族
s.type 返回套接字类型
s.proto 返回套接字协议

三、思路

TCP服务器创建:(伪代码)

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

TCP客户端创建:(伪代码)

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


UDP服务器创建:(伪代码)

        ss=socket() #创建服务器套接字
        ss.bind()       #绑定服务器套接字
        inf_loop:       #服务器无限循环
            cs=ss.recvfrom()/ss.sendto()    #关闭(接收/发送)
        ss.close()      #关闭服务器套接字

UDP客户端创建:(伪代码)

        cs=socket() #创建客户端套接字
        comm_loop:  #通信循环
            cs.sendto()/cs.recvfrom()   #对话(发送/接收)
        cs.close()      #关闭客户端套接字

四、实例

(一)TCP实例

服务器:(SerTcp.py)

import socket       #导入socket模块

HOST='localhost'    #服务器主机名/IP
PORT=21567          #服务器通信端口
BUFSIZ=1024         #缓冲区大小
ADDR=(HOST,PORT)    #创建套接字地址元组

tcpSerSock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #创建TCP类型的服务器套接字
tcpSerSock.bind(ADDR)   #套接字绑定地址元组
tcpSerSock.listen(5)    #监听连接,设置可挂起最大数为5

while True:
    print("waiting for connection...")
    tcpCliSock,addr=tcpSerSock.accept()     #阻塞式地等待连接,若成功连接则返回与客户端通信的新套接字和客户端地址元组
    print("...connected from {ADDR}".format(ADDR=addr))

    while True:
        data1=tcpCliSock.recv(BUFSIZ)   #接收客户端的数据
        if not data1:
            break
        data2='nihao!'
        data2=bytes(data2,'utf-8')  #TCP以字节形式分片传输,所以将数据提前编码
        #上个语句也可以换成data2=data2.encode(encoding='UTF-8')
        tcpCliSock.send(data2)  #向客户端发送数据

    tcpCliSock.close()  #关闭与某个客户端的套接字,继续回到外层循环进行监听
    
tcpSerSock.close()  #当服务器不再监听时,关闭服务器套接字

客户端:(CliTcp.py)

import socket           #导入socket模块

HOST='localhost'        #需要访问的服务器主机名/IP
PORT=21567              #需要访问的服务器通信端口
BUFSIZ=1024             #缓冲区大小
ADDR=(HOST,PORT)        #创建套接字地址元组

tcpCliSock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)     #创建TCP类型的客户端套接字
tcpCliSock.connect(ADDR)    #连接地址元组为ADDR的套接字

while True:
    data1=input(">")    #输入需要发送的数据
    if not data1:
        break
    data1=data1.encode(encoding='UTF-8')    #TCP以字节形式分片传输,所以将数据提前编码
    tcpCliSock.send(data1)      #向服务器发送数据
    data2=tcpCliSock.recv(BUFSIZ)   #接收服务器的数据
    if not data2:
        break
    #将收到的服务器数据解码并打印
    data2=data2.decode(encoding='UTF-8')    
    print(data2)
    
tcpCliSock.close()  #关闭客户端套接字

(一)UDP实例

服务器:(SerUdp.py)

import socket           #导入socket模块

HOST='localhost'        #服务器主机名/IP
PORT=21567              #服务器通信端口
BUFSIZ=1024             #缓冲区大小
ADDR=(HOST,PORT)        #创建套接字地址元组

udpSerSock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #创建UDP类型的服务器套接字
udpSerSock.bind(ADDR)   #套接字绑定地址元组
#UDP与TCP不同,这里不需要设置监听

while True:
    print('waiting for message...')     #与TCP不同,这里等待的是message,而不是connection
    #与TCP不同,用来发送和接收数据的套接字为服务器的套接字
    data1,addr=udpSerSock.recvfrom(BUFSIZ)  #当接收到某客户端的消息时,返回数据和客户端地址元组
    data2='nihao!'
    data2=bytes(data2,'utf-8')  #TCP以字节形式分片传输,所以将数据提前编码
    udpSerSock.sendto(data2,addr)   #与TCP不同,由于UDP无连接,所以发送数据时需要加上客户端的地址元组
    print('...received from and returned to:',addr)     #打印客户端的地址元组

udpSerSock.close()  #关闭服务器套接字

客户端:(CliUdp.py)

import socket           #导入socket模块

HOST='localhost'        #服务器主机名/IP
PORT=21567              #服务器通信端口
BUFSIZ=1024             #缓冲区大小
ADDR=(HOST,PORT)        #创建套接字地址元组

udpSerSock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #创建UDP类型的服务器套接字
udpSerSock.bind(ADDR)   #套接字绑定地址元组
#UDP与TCP不同,这里不需要设置监听

while True:
    print('waiting for message...')     #与TCP不同,这里等待的是message,而不是connection
    #与TCP不同,用来发送和接收数据的套接字为服务器的套接字
    data1,addr=udpSerSock.recvfrom(BUFSIZ)  #当接收到某客户端的消息时,返回数据和客户端地址元组
    data2='nihao!'
    data2=bytes(data2,'utf-8')  #TCP以字节形式分片传输,所以将数据提前编码
    udpSerSock.sendto(data2,addr)   #与TCP不同,由于UDP无连接,所以发送数据时需要加上客户端的地址元组
    print('...received from and returned to:',addr)     #打印客户端的地址元组

udpSerSock.close()  #关闭服务器套接字
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,451评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,172评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,782评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,709评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,733评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,578评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,320评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,241评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,686评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,878评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,992评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,715评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,336评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,912评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,040评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,173评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,947评论 2 355

推荐阅读更多精彩内容