Python学习笔记——Day07

Python学习笔记——Day07

第七天,今天看网络编程相关。前两天因工作需要,耽误了博客更新。

socket的使用

socket(简称套接字)是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机之间的进程间通信,我们网络上很多服务都是基于Socket完成通信的。

在Python中使用socket模块的函数socket就可以

import socket
socket.socket(AddressFamily,Type)

首先socket.socket创建一个socket,该函数需要两个参数:

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

比如我要是创建一个tcp socket,就这样写

import socket

# 创建tcp的套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 功能代码 略...
...

# 当逻辑结束后,关闭socket
s.close()

创建udp套接字的话只需要将socket方法中的第二个参数,换为socket.SOCK_DGREAM

import socket

# 创建udp的套接字
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 功能代码 略...
...

# 当逻辑结束后,关闭socket
s.close()

使用套接字流程简单说就是

  1. 创建套接字
  2. 使用套接字进行接收/发送数据
  3. 关闭套接字

是不是有点眼熟?第四天中文件操作和这个流程有些相似,先打开文件,操作文件,然后调用close()方法关闭,那时候我只写了一个小小的例子,明天周日详细总结一份文件操作相关的内容。

创建udp的发送/接收数据

socket简单发送接收程序

循环接收代码

#!usr/bin/python
# -*- coding: utf-8 -*-
# author: 李爽
# description:socket接收
import socket


def main():
    # 创建udp socket
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 绑定端口
    local_addr = ("127.0.0.1", 8080)
    s.bind(local_addr)

    # 循环接收
    while True:

        # 接收数据,返回的是一个元组(接收到的数据,(发送方的地址信息))
        recv_message = s.recvfrom(1024)
        recv_data = recv_message[0]
        recv_address = recv_message[1]
        # 打印结果
        print("从%s接收:%s" % (recv_address, recv_data.decode("utf-8")))
        # 如果接收的是quit
        if recv_data.decode("utf-8") == 'quit':
        	print("接收程序退出")
            break
    s.close()


if __name__ == "__main__":
    main()

循环发送代码

#!usr/bin/python
# -*- coding: utf-8 -*-
# author: 李爽
# description:udp socket 发送
import socket


def main():
    # 创建udp socket
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    while True:
        # 键盘录入要发送的数据
        send_data = input("请输入要发送的数据:")

        # 发送数据,
        send_addr = ("127.0.0.1", 8080)
        s.sendto(send_data.encode("utf-8"), send_addr)
        # 若输入quit 退出程序
        if send_data == "quit":
            print("发送程序退出")
            break
    s.close()


if __name__ == "__main__":
    main()

程序运行结果

发送程序

请输入要发送的数据:你好
请输入要发送的数据:quit
发送程序退出
接收程序

从('127.0.0.1', 62189)接收:你好
从('127.0.0.1', 62189)接收:quit
接收程序退出

流程还是那套流程,创建套接字,使用套接字进行收发数据,关闭套接字,只不过加上了死循环,在输入quit的时候退出程序,需要注意的是,字符串进行了编码和字节码进行了解码,使用的str.encode(encoding="utf-8", errors="strict")``bytes.decode(encoding="utf-8", errors="strict"),其中encoding是指在编码解码过程中使用的编码,例如我使用的是utf-8,errors是指错误的处理方案。具体的可以参照官方文档。还有就是udp接收和发送的流程有一些不一样的,接收多一步socket.bind()参数传了一个元组,是ip和端口的元组,其实也可以不绑定端口,但这种情况下是操作系统随机分配的端口,当重新运行程序的时候端口可能会发发生变化,但作为一个服务器端的程序,端口总是变化的话,客户端的我们还要每天改端口,这就是我们做这一步端口绑定的目的。

案例-udp聊天室

#!usr/bin/python
# -*- coding: utf-8 -*-
# author: 李爽
# description:udp 聊天室
import socket


def send_msg(s):
    send_ip = input("请输入要发送的IP地址:")
    send_port = int(input("请输入要发送的端口号:").strip())
    send_message = input("请输入要发送的信息:")
    s.sendto(send_message.encode("utf-8"), (send_ip, send_port))


def recv_msg(s):
    recv_message = s.recvfrom(1024)
    recv_data = recv_message[0].decode("utf-8")
    recv_addr = recv_message[1][0] + ": " + str(recv_message[1][1])
    print("从%s接收消息:%s" % (recv_addr, recv_data))


def main():
    # 创建udp socket
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.bind(("", 8080))
    while True:
        print("欢迎进入聊天室")
        print("1.发送消息")
        print("2.接收消息")
        print("0.退出聊天室")
        op = input("请输入操作:")
        if op == "1":
            # 发送
            send_msg(s)
        elif op == "2":
            # 接收
            recv_msg(s)
        elif op == "0":
            print("退出聊天室")
            break
        else:
            print("输入有误,请重新输入。")
    s.close()


if __name__ == "__main__":
    main()

发送给自己的输出结果

欢迎进入聊天室
1.发送消息
2.接收消息
0.退出聊天室
请输入操作:1
请输入要发送的IP地址:127.0.0.1
请输入要发送的端口号:8080
请输入要发送的信息:haha
欢迎进入聊天室
1.发送消息
2.接收消息
0.退出聊天室
请输入操作:2
从127.0.0.1: 8080接收消息:haha
欢迎进入聊天室
1.发送消息
2.接收消息
0.退出聊天室
请输入操作:0
退出聊天室

这样我们的小聊天室就完成了!可是这个小聊天室有一个很严重的问题,如果你知道请在文章后面回复给我,答案我也会在下一篇博客中揭晓

TCP套接字

TCP套接字就是使用TCP协议提供的传输服务来实现网络通信的编程接口。只需要将socket方法的第二个参数设置为SOCK.STREAM就可以得到一个TCP套接字。由于一台主机可能拥有多个IP地址,而且很有可能会配置多个不同的服务,所以作为服务器端的程序,需要在创建套接字对象后将其绑定到指定的IP地址和端口上。
下面来看服务器端和客户端

#!usr/bin/python
# -*- coding: utf-8 -*-
# author: 李爽
# description:tcp 套接字服务器端
import socket


def main():
    # 创建tcp套接字
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 绑定端口
    s.bind(("127.0.0.1", 8080))
    # socket创建的套接字默认属性是为主动的
    # 将套接字的属性变为被动,接收发送来的数据
    s.listen(1024)
    # 当有客户端连接到服务器时,就产生一个新的套接字专门来为这个客户端服务
    # client_socket 为这个客户端服务的套接字
    # 而s则继续等待其他客户端连接
    client_socket, client_addr = s.accept()
    # 接收数据
    recv_data = client_socket.recv(1024)
    print("从%s接收到的数据为:%s" % (client_addr, recv_data.decode("utf-8")))
    # 返回数据到客户端
    client_socket.send("收到啦!".encode("utf-8"))
    # 关闭服务于这个客户端的套接字,关闭后,就意味着只能重新连接才能再次开启服务
    client_socket.close()


if __name__ == "__main__":
    main()

客户端

#!usr/bin/python
# -*- coding: utf-8 -*-
# author: 李爽
# description:tcp 套接字客户端
import socket


def main():
    # 创建tcp套接字
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 连接服务器
    s.connect(("127.0.0.1", 8080))
    # 发送数据
    send_msg = input("请输入要发送的信息:")
    s.send(send_msg.encode("utf-8"))
    # 接收数据
    recv_data = s.recv(1024)
    print("从服务器接收到的数据为:%s" % recv_data.decode("utf-8"))
    # 关闭套接字
    s.close()


if __name__ == "__main__":
    main()

可以在服务器端加上死循环,循环接收消息。在此不再赘述。需要注意的是

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

结语

socket编程简介到此就结束了。
如果你发现我的文章哪里有错误或者有什么好的想法可以联系我,我们一起学习共同进步,我的邮箱地址是[email protected]

let’s do more of those!

发布了26 篇原创文章 · 获赞 2 · 访问量 2340

猜你喜欢

转载自blog.csdn.net/qq_42909545/article/details/103180813