python网络编程

什么是 Socket?

Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。

socket()函数

Python 中,我们用 socket() 函数来创建套接字,语法格式如下:

socket.socket([family[, type[, proto]]])

参数

  • family: 套接字家族可以是 AF_UNIX (文件类型的套接字)或者 AF_INET(网络型套接字ipv4)还有AF_INET6(用于 IPv6 网络通信)
  • type: 套接字类型可以根据是面向连接的还是非连接分为SOCK_STREAM(UDP方式)SOCK_DGRAM(TCP方式)
  • proto: 一般不填默认为0.

什么是UDP

UDP(User Datagram Protocol,用户数据报协议)是一种无连接的协议,用于在IP主机和应用程序之间发送数据报。与TCP(Transmission Control Protocol,传输控制协议)不同,UDP不提供数据报的排序、重传或确认机制,因此被称为不可靠的协议。

UDP的主要特点如下:

  1. 无连接:UDP不建立连接,可以直接发送数据报,不需要像TCP那样进行三次握手建立连接。
  2. 不可靠:UDP不保证数据报的顺序、重传或确认,因此可能会出现数据丢失、乱序或重复的情况。
  3. 面向报文:UDP将应用程序发送的数据分成多个数据报,每个数据报独立发送,并在接收端重新组合成原始数据。
  4. 速度快:由于UDP没有确认机制和重传机制,因此它的传输速度通常比TCP更快。
  5. 头部开销小:UDP的数据报头部开销只有8个字节,相比之下TCP的头部开销为20个字节。

使用UDP实现一个聊天器系统

 主要功能:

1、向指定主机和端口发送消息

2、指定接收消息的端口并接收消息、

3、使用多线程方法一直接收消息

主要方法:

1、创建UDP套接字

udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

2、绑定接收端口

udp_socket.bind(("", 8888))

3、发送消息

因为计算机间的通信是二进制的,需要使用encode()方法将发送的数据转为二进制

udp_socket.sendto(send_str.encode(), (ip_str, port))

4、接收消息

recvfrom的返回值是一个元组,接收到的消息分为两部分,一部分是消息内容,一部分是发送方的ip和端口。同样的接收到的消息需要使用decode()方法解码

data = udp_socket.recvfrom(1024)
import socket
import threading
"""UDP聊天器"""


def Socket_Sento(udp_socket):
    ip_str = input("请输入对方的ip地址:")
    port = int(input("请输入对方的端口号:"))
    send_str = input("请输入要发送的内容:")
    udp_socket.sendto(send_str.encode(), (ip_str, port))


def Socket_Recvfrom(udp_socket):
    while True:
        data = udp_socket.recvfrom(1024)
        print("来自主机:%s:%d发来的消息:%s\n" % (data[1][0], data[1][1], data[0].decode("gbk")))


def main():
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.bind(("", 8888))
    t1 = threading.Thread(target=Socket_Recvfrom, args=(udp_socket,), daemon=True)
    t1.start()
    while True:
        print("\n\n***************************")
        print("******  1、发送信息  *******")
        print("******  2、退出系统  *******")
        print("***************************")
        num = input("请选择功能序号\n")
        if num == "1":
            Socket_Sento(udp_socket)
        elif num == "2":
            break
        else:
            print("输入错误")
    udp_socket.close()


if __name__ == "__main__":
    main()

什么是TCP

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。

使用TCP时与UDP不同,需要先建立连接

tcp_client_socket.connect(("192.168.56.1",8080))

使用TCP模拟客户端

import socket
# 创建套接字
tcp_client_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 建立连接
tcp_client_socket.connect(("192.168.56.1",8080))
# 发送数据
tcp_client_socket.send("约吗".encode())
# 接收数据
print(tcp_client_socket.recv(1024).decode("gbk"))

tcp_client_socket.close()

使用TCP模拟服务器端

当TCP作为服务端的时候需要设置地址重用、绑定端口、设置监听

tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
tcp_server_socket.bind(("", 8080))
tcp_server_socket.listen(128)
import socket
import threading
"""多线程TCP服务框架"""

def recv_msg(new_socket, client_port):
    while True:
        recv_data = new_socket.recv(1024)
        if recv_data:
            print("来自[%s]发送的数据:%s" % (client_port, recv_data.decode("gbk")))
        else:
            print("客户端已断开连接")
            break


tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置地址重用
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 绑定端口
tcp_server_socket.bind(("", 8080))
# 设置监听
tcp_server_socket.listen(128)
# 循环实现多个客户端连接
while True:
    new_socket, client_port = tcp_server_socket.accept()
    print("与%s连接成功" % str(client_port))
    recv_thread = threading.Thread(target=recv_msg, args=(new_socket, client_port), daemon=True)
    recv_thread.start()

# tcp_server_socket.close()

使用TCP模拟浏览器发送请求并接收服务器的响应数据

浏览器的请求分为get请求和post请求

get请求的请求协议包含请求行、请求头、请求空行

post请求的请求协议包含请求行、请求头、请求空行、请求内容

import socket
# 创建套接字
tcp_client_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

# 建立连接
tcp_client_socket.connect(("127.0.0.1",8080))

# 拼接请求协议
# 请求行
request_line="GET / HTTP/1.1\r\n"
#请求头
request_header="Host:www.baidu.com\r\n"
#请求空行
requset_blank="\r\n"
request_data=request_line+request_header+requset_blank
#发送请求协议
tcp_client_socket.send(request_data.encode())
#接收服务器响应内容

respon_data=tcp_client_socket.recv(4096).decode()
html_data=respon_data[respon_data.find("\r\n\r\n")+4:]
print(html_data)
# 保存内容

with open("D:\\PycharmProjects\\TextProject\\Text_TCP_Web\\index.html","w") as file:
        file.write(html_data)

#关闭连接
tcp_client_socket.close()

使用TCP设计服务器返回固定数据

首先需要解码请求协议,将接收到的请求解码拆分得到要请求的内容

然后创建响应协议:响应行、响应头、响应空行、响应主体,最后拼接发送给请求端

import socket


def request_headler(new_client_socket, ip_port):
    request_data = new_client_socket.recv(1024).decode()
    # print(request_data)
    # 接收客户端浏览器发送的请求
    # 判断协议是否为空
    if not request_data:
        print("%s用户已下线" % str(ip_port))
        new_client_socket.close()
        return
    # 根据客户端浏览器请求的资源路径,返回请求资源
    # 把请求协议解码,得到请求报文的字符串
    # 得到请求行
    # 查找第一个\r\n出现得位置
    # 使用切片获取请求行
    requst_line = request_data[0:request_data.find("\r\n")]
    # 按空格分割创建数组
    requst_line_list = requst_line.split(" ")
    # 获取到指定文件
    file_path = requst_line_list[1]
    # 如果没有指定访问的文件就返回默认首页
    if file_path == "/":
        file_path = "index.html"
    print("[%s]用户请求了%s资源" % (str(ip_port), file_path))
    # 拼接响应的报文
    # 响应行
    respon_line = "HTTP/1.1 200 OK\r\n"
    # 响应头
    respon_header = "Server:Python\r\n"
    # 响应空行
    respon_blank = "\r\n"
    # 响应主体
    # respon_body = "Hello Wolrd"
    # 返回指定页面
    try:
        with open("..\\static\\" + file_path, "rb") as file:
            respon_body = file.read()
    except Exception as e:
        respon_line = "HTTP/1.1 404 Not Found\r\r"
        respon_body = "Error! (%s)" % e
        respon_body = respon_body.encode()
    # 发送响应报文
    respon_data = (respon_line + respon_header + respon_blank).encode() + respon_body
    new_client_socket.send(respon_data)


def main():
    # 创建套接字
    tcp_sderver_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 设置端口重用、
    tcp_sderver_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
    # 绑定端口
    tcp_sderver_socket.bind(("", 8080))
    # 设置监听,让套接字由主动变为被动接收
    tcp_sderver_socket.listen(128)
    # 接受客户端的请求  定义函数request_handler()
    while True:
        new_client_socket, ip_port = tcp_sderver_socket.accept()
        print("新用户%s来了" % str(ip_port))
        request_headler(new_client_socket, ip_port)
    # 关闭操作
    tcp_sderver_socket.close()


if __name__ == "__main__":
    main()

使用TCP模拟客户端从服务器端下载文件功能

客户端代码

import socket
clinent_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
clinent_socket.connect(("192.168.56.1",8080))
file_name=input("请输入要下载的文件名:")
clinent_socket.send(file_name.encode())

with open("C:\\Users\\Administrator\\Desktop\\copy\\"+file_name, "wb") as source_file:
    while True:
        file_data = clinent_socket.recv(1024)
        if file_data:
            source_file.write(file_data)
        else:
            break
clinent_socket.close()

服务端代码

import socket
server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_socket.bind(("",8080))
server_socket.listen(128)
while True:
    new_server_socket,clinet_port=server_socket.accept()
    print("客户端[%s]已连接"%str(clinet_port))
    clinet_data=new_server_socket.recv(1024)
    try:
        with open("C:\\Users\\Administrator\\Desktop\\"+clinet_data.decode(),"rb") as server_file:
            while True:
                file_date=server_file.read(1024)
                if file_date:
                    new_server_socket.send(file_date)
                else:
                    print("文件传输完成")
                    break
    except Exception as e:
        print("文件%s传输失败"%clinet_data.decode())
    new_server_socket.close()

server_socket.close()

你可能感兴趣的:(python,网络,开发语言)