python网络编程

1. 网络编程基础

2. 套接字

套接字是一种“通信端点”,网络化的应用程序在开始任何通讯之前需要创建套接字。套接字分类:

面向连接的套接字:在通讯之前建立一条连接,也称为流套接字。面向连接的通信方式提供了可靠的、顺序的、不会重复的数据传输,也不会被加上数据边界。这也代表每个发送的消息可能会被拆为多份,没有顺序地正确到达目的地,然后被重新拼接起来。实现这种连接的主要协议是传输控制协议(TCP)。创建TCP套接字需要指定套接字类型为SOCK_STREAM。

无连接即数据报型的无连接套接字。即无需建立连接就可进行通讯,但此时数据到达的顺序、完整性及不重复性无法保证。数据报会保留数据边界,即数据是整个发送的。实现这种连接的主要协议是用户数据报协议(UDP)。创建UDP套接字需要指定套接字类型为SOCK_DGRAM。

2.1 套接字使用:

套接字使用流程和文件很相似:创建套接字、使用套接字收发数据、关闭套接字。

python使用socket()模块来创建套接字,完成基于套接字的网络通信。

函数 socket.socket() 创建一个 socket,该函数带有两个参数:

  • Address Family:可以选择 AF_INET(用于 Internet 进程间通信) 或者 AF_UNIX(用于同一台机器进程间通信),实际工作中常用AF_INET
  • Type:套接字类型,可以是 SOCK_STREAM(流式套接字,主要用于 TCP 协议)或者 SOCK_DGRAM(数据报套接字,主要用于 UDP 协议)

套接字中常用的函数如下:

image
image
2.2 udp套接字

udp通信模型

img

udp服务器

recvfrom方法:

  • data, addr = server_socket.recvfrom()
  • 方法返回两个值,第一个值为接收到的二进制数据,第二个数据是一个元组形式(IP, PORT),标记客户端的地址。第一个元素为客户端的IP地址字符串,第二个元素为客户端端口号。

sendto方法:

  • server_socket.sentto(data, addr)
  • sendto方法接受两个参数,第一个为发送的数据(二进制形式,需要编码),第二个为客户端的地址(从recvfrom方法得到)
img
import socket

# 定义服务器IP及端口
HOST = ""  # 字符串留空或者localhost代表本地,也可自定义Ip
PORT = 7890
ADDR = (HOST, PORT)

def main():
    # 定义服务器套接字
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # 绑定地址
    server_socket.bind(ADDR)

    # 通信循环:收发消息
    while True:
        print("waiting for messages......")

        # 接受客户端消息
        recv_data, addr = server_socket.recvfrom(1024)
        print("receive messages:%s from %s" % (recv_data.decode("gbk"), str(addr)))

        if recv_data.decode("gbk") == "exit":
            break

        # 发送消息到客户端
        send_data = "我是UDP服务器,已接收到你发来的消息!"
        server_socket.sendto(send_data.encode("gbk"), addr)

    # 关闭服务端套接字
    server_socket.close()

if __name__ == '__main__':
    main()

udp客户端

img
import socket

# 定义要连接的服务端地址
HOST = ""
PORT = 7890
ADDR = (HOST, PORT)

def main():

    # 定义客户端套接字
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # 通信循环:收发消息
    while True:
        # 客户端先发送消息
        send_data = input("请输入要发送的数据:")

        if not send_data:
            break

        client_socket.sendto(send_data.encode("gbk"), ADDR)

        recv_data, addr = client_socket.recvfrom(1024)

        # 打印服务器发过来的数据
        print(recv_data.decode("gbk"))

    # 关闭客户端套接字
    client_socket.close()

if __name__ == '__main__':
    main()
2.3 tcp套接字

tcp通信模型

img

TCP服务器

伪代码:

img

server_socket.accept方法:

  • tmp_socket, addr = server_socket.accept()
  • 该方法返回两个数据,第一个为一个临时的套接字用于标记当前连接的客户端及用来与客户端进行通信;第二个为当前连接客户端的地址信息(ip,port)
img
import socket

# 定义服务器地址:主机名/ip、端口号
Host = ''
PORT = 7890
ADDR = (Host, PORT)

def main():

    # 定义TCP套接字
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 绑定地址
    server_socket.bind(ADDR)

    # 开始监听(变为被动)
    server_socket.listen(128)

    # 通信循环:用来循环接受客户端连接
    while True:

        # 接受客户端连接
        tmp_socket, addr= server_socket.accept()  # 返回一个临时套接字(用于客户端通信)及客户端的地址
        print("connect from :", addr)

        # 通信循环:使用临时套接字收发数据
        while True:
            recv_data = tmp_socket.recv(1024)

            if not recv_data:
                break

            print(recv_data.decode("gbk"))

            send_data = "我是一个TCP服务器!!"
            tmp_socket.send(send_data.encode("gbk"))

        tmp_socket.close()  # 关闭临时套接字

    server_socket.close()  # 关闭监听套接字


if __name__ == '__main__':
    main()

TCP客户端

伪代码:

img
img
import socket

# 定义要连接的服务器端地址
Host = ""
PORT = 7890
ADDR = (Host, PORT)

def main():

    # 定义tcp客户端套接字
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 连接tcp服务器
    client_socket.connect(ADDR)

    # 通信循环:收发数据

    while True:

        send_data = input("请输入要发送的数据:")

        # 发送数据给服务器
        client_socket.send(send_data.encode("gbk"))

        # 从服务器接收数据并打印
        recv_data = client_socket.recv(1024)

        if not recv_data:
            break
        print(recv_data.decode("gbk"))

    client_socket.close()

if __name__ == '__main__':
    main()

tcp注意点

  • tcp服务器一般情况下都需要绑定,否则客户端找不到这个服务器
  • tcp客户端一般不绑定,因为是主动链接服务器,所以只要确定好服务器的ip、port等信息就好,本地客户端可以随机
  • tcp服务器中通过listen可以将socket创建出来的主动套接字变为被动的,这是做tcp服务器时必须要做的
  • 当客户端需要链接服务器时,就需要使用connect进行链接,udp是不需要链接的而是直接发送,但是tcp必须先链接,只有链接成功才能通信
  • 当一个tcp客户端连接服务器时,服务器端会有1个新的套接字,这个套接字用来标记这个客户端,单独为这个客户端服务
  • listen后的套接字是被动套接字,用来接收新的客户端的链接请求的,而accept返回的新套接字是标记这个新客户端的
  • 关闭listen后的套接字意味着被动套接字关闭了,会导致新的客户端不能够链接服务器,但是之前已经链接成功的客户端正常通信。
  • 关闭accept返回的套接字意味着这个客户端已经服务完毕
  • 当客户端的套接字调用close后,服务器端会recv解堵塞,并且返回的长度为0,因此服务器可以通过返回数据的长度来区别客户端是否已经下线

tcp的三次握手及四次挥手

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

推荐阅读更多精彩内容