01.相关知识预备阶段

02.udp

        02.1udp发送信息

        02.2udp接收数据

        02.3代码演示阶段

03.tcp

        03.1tcp客户端

        03.2tcp服务器

        03.3代码演示阶段

04.udp应用

05.tcp应用


01.相关知识预备阶段

1.查看网卡信息: ipconfig(windows)

ifconfig(linux)


2.Linux下查看端口命令:netstat -na


3.想通过网络进行信息交流必须知道交流双方的IP及port(端口),ip使你确定是在跟哪太电脑通信,而port使你确定和该电脑的哪个进程进行通信

4.socket (简称 套接字) 是进程之间通信一个工具,好比现实生活中的插座,所有的家用电器要想工作都是基于插座进行,进程之间想要进行网络通信需要基于这个 socket(负责进程间的网络数据传输好比数据的搬运工),所以本次程序的实现全部都要导入socket模块,本模块由python自带无需下载。

5.ip地址发展到至今有IPv4和v6之分本次全部以ipv4为准

6.网络通信的方式有两个:第一即udp通信也可以说是点对点通信,第二即tcp通信也称客户-服务端通信

7.本次采用虚拟机和电脑双开,来验证代码

8.代码的注释是主要的讲解部分


02.1udp发送信息

  • # 导入模块
    import socket  
    
    def main():
        # 1.创建udp套接字
        udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
        # socket.AF_INET代表选择IPv4,socket.SOCK_DGRAM数据报套接字
        # 2.创建发送的地址还有端口---元组,(ip, port)
        udp_address = ("192.168.43.39", 8080)
        # 3.使用udp.sendto()发送数据,b" "即字节类型
        udp_socket.sendto(b'haha', udp_address)
        # 4.关闭套接字,释放信道的占用
        udp_socket.close()
    
    
    if __name__ == "__main__":
        main()
    
    """
    
    sendto()函数的讲解sendto(1, (2)) 1处填发送的数据以字符串形式,2处以元组的形式(ip,port)告诉电脑接收方的IP及port
    
    b'haha'----bytes类型的数据在网络通信中都需要把数据转换成字节类型
    
    """

     代码1 

import socket

def main():
    # 1.创建udp套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 从键盘中获取数据
    send_data = input("请输入要发送的数据")
    # 创建发送的地址还有端口元组,(ip, port)
    udp_address = ("192.168.119.128", 7788)
    # 2.encode("utf-8")编码格式
    udp_socket.sendto(send_data.encode("utf_8"), udp_address)
    # .关闭
    udp_socket.close()


if __name__ == "__main__":
    main()

"""

本段代码和上一段差不多主要的改动在于不是直接字节类型发送,而是以utf-8的方式进行编码这样发送的数据还是字节类型,如此就

解决了发送任意数据的需求
"""

 代码2

 对于上段代码编码及解码的实验

 下面代码通过循环实现udp多次发送数据,外面while True实现死循环里面通过检测到输入exit即退出循环

import socket

def main():
    # 1.创建udp套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    while True:
        # 从键盘中获取数据
        send_data = input("请输入要发送的数据")
        if send_data == "exit":
            break
        else:
            pass
        # 创建发送的地址还有端口元组,(ip, port)
        udp_address = ("192.168.31.8", 8080)
        # 2.encode("utf-8")编码格式
        udp_socket.sendto(send_data.encode("utf-8"), udp_address)

    # .关闭
    udp_socket.close()


if __name__ == "__main__":
    main()

 代码3


02.2udp接收信息

import socket


def main():
    # 1.创建一个udp套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 2.绑定端口
    local_address = ("192.168.43.39", 7788)
    udp_socket.bind(local_address)
    # 3.接收数据1024为接收的最大数
    recv_data = udp_socket.recvfrom(1024)
    # 4.打印接受的数据
    print(recv_data)
    # 5.关闭套接字
    udp_socket.close()


if __name__ == '__main__':
    main()
"""
绑定本地端口是你接收数据的前提我们知道一个电脑是有很多端口的只有绑定一个端口你才知道哪个数据发送给你
"""

 代码4

以上代码讲解:

        1.用bind()来绑定ip及端口bind((ip, port))里面是一个ip和port的元组且注意ip以str格式,port以int格式

        2.使用recvfrom来接收数据recvfrom(1024)里面的1024指限定一次性最大接收1024个字节

        3.代码中的recv_data来接收recvfrom的返回值,将会得到一个如:(b'6\n', ('192.168.239.1', 8080))的元组

import socket


def main():
    # 1.创建一个udp套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 2.绑定端口
    local_address = ("", 7788)
    udp_socket.bind(local_address)
    print("绑定端口成功!")
    # 3.接收数据1024为接收的最大数
    print('等待对方发信息给本机')
    recv_data = udp_socket.recvfrom(1024)
    print("数据以接收")
    # 对接收的数据进行处理(b'6\n', ('192.168.239.1', 8080))
    recv_msg = recv_data[0]  # 存储接收到的数据
    send_address = recv_data[1]  # 存储接收到的ip port
    # 4.打印接受的数据
    print('{0[0]:}: {1:}'.format(send_address, recv_msg.decode('utf-8')))
    # ('192.168.239.1', 8080):b'6\n'  
    # 5.关闭套接字
    udp_socket.close()
if __name__ == "__main__":
    main()

  代码5

 讲解:

        1.本代码相对于上一段来说多了对接收的数据处理部分绑定端口处代码直接bind("", 7788)

偷懒的方式这样计算机会自动找本机ip       

        2.由上面使用了utf-8方式进行编码故这里使用utf-8进行解码


 02.3代码演示

windows代码                                                                                                                              

  windows程序结果

 

 linux代码                                                                                   

 

    linux程序启动


03.1tcp客户端

import socket


def main():
    # 创建tcp套接字
    tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 链接
    tcp_socket.connect(('192.168.31.8', 8080))
    # 发送数据
    tcp_socket.send('你好'.encode('utf-8'))
    # 关闭套接字
    tcp_socket.close()


if __name__ == '__main__':
    main()

   代码6

解析: 

        1.创建流式套接字tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        2.与服务器进行链接tcp_socket.connect(('192.168.31.8', 8080))函数connect里面为服务器ip,port

        3.tcp_socket.send('你好'.encode('utf-8'))本此使用send而不是sendto他们的区别在于send不要填第二个参数(对方电脑的ip及port)。原因是客户端已经先链接了不需要再次使用sendto引入对方ip及port

        4.tcp_socket.send('你好'.encode('utf-8'))里面的参数为元组形式


03.1tcp服务器

import socket


def main():
    # 1.socket创建一个套接字
    tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2.bind绑定ip和端口
    tcp_socket.bind(("192.168.43.39", 8080))
    # 3.listen使套接主动变为可以被动链接
    tcp_socket.listen(128)
    i = 2
    # 循环目的:调用多次accept从而为多个客户端服务
    while i:
        i -= 1
        print('等待一个新的客户端的到来......')
        # 4.accept等待客户端的链接返回值是一个元组
        new_client_tcp, client_address = tcp_socket.accept()
        print("一个新的客户端已到来")
        print(new_client_tcp, client_address)
        print(client_address)  # ('192.168.239.1', 55723)
        print(new_client_tcp)  # <socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.239.131', 8081), raddr=('192.168.239.1', 55723)>
        while True:
            # 为一个客户端服务多次
            # 5.recv,send接收发送的数据
            recv_data = new_client_tcp.recv(1024)
            print(recv_data)  # (b'\xc4\xe3\xba\xc3', None)
            if recv_data:  # b''= None
                # 回发送一部分数据给客户端
                new_client_tcp.send("haha------ok-----".encode('utf-8'))
            else:
                break
            print(recv_data)  # (b'\xc4\xe3\xb9\xfe\xe7\xea\n', None)
            print('客户端发送过来的消息是: %s' % (recv_data.decode('gbk')))  # 对0方是window编码故gbk
            # 判断recv_data是因为啥解堵塞,1.客户端发送数据过来或者客户端关闭

        # 关闭套接字
        new_client_tcp.close()
        print('本次服务结束')
    tcp_socket.close()


if __name__ == '__main__':
    main()

代码7

解析:

        1.因为是服务器必须绑定端口这样与用户端使用connecct链接相呼应,只有你服务器端固定了用户端才知道要链接电脑上的哪个端口。

        2.listen使套接主动变为可以被动链接tcp_socket.listen(128)并且参数固定了可链接的电脑的数量

        3.本程序为了可以终止使用了i = 2来使他只被链接两次

        4.new_client_tcp, client_address = tcp_socket.accept()本代码等待用户链接,用户链接了以后返回一个元组,元组的第一个元素为服务器创建的一个新的套接字用来专门服务本次链接的客户端,第二个元素为用户端ip,port

        5.if recv_data:

                   new_client_tcp.send("haha------ok-----".encode('utf-8'))
            else:
                break

        本段代码如果客户端断开链接,服务器会接收到recv_data=b""等同于None此时会退出循环为了确保我服务器接收到了用户发的信息,new_client_tcp.send("haha------ok-----".encode('utf-8'))给用户回了一个信息。同时也是因为之前链接了故此处无需使用sendto()----加入参数目标ip及port


03.3代码演示阶段

windows代表服务器端代码

 linux代表用户端代码

 Linux执行了两遍后windows程序结果


04.udp应用 

import socket


# 创建一个套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
count = 1
while True:
    try:
        udp_port = int(input('请输入一个端口用于程序通信'))
        # 绑定本地端口
        udp_socket.bind(("", udp_port))
        print('绑定端口成功')
        break
    except:
        print('该端口可能被占用请重新输入,以重新输入一次,三次自动退出程序(这是第{:}次)'.format(count))
        if count == 3:
            udp_socket.close()
            exit()
        else:
            count += 1


def udp_sendto():
    print('{:-^20}'.format('欢迎来到发送信息界面'))
    other_ip = input('请输入对方ip')
    other_port = int(input('请输入对方电脑port'))
    while True:
        send_msg = input('请输入要发送的数据,输入exit退出')
        if send_msg == 'exit':
            udp_socket.sendto(b'', (other_ip, other_port))
            break
        else:
            udp_socket.sendto(send_msg.encode('utf-8'), (other_ip, other_port))


def udp_recv():
    print('{:-^20}'.format('欢迎来到接收信息界面'))
    msg = 1
    while msg:
        print('正在接收数据中')
        msg, address = udp_socket.recvfrom(1024)
        if msg == b'':
            print('对方电脑已停止发送信息')
            break
        print('已接收来自ip{:}port{:}的数据:{:}'.format(address[0], address[1], msg.decode('utf-8')))
        msg = int(input('继续接收?非0继续,0退出'))
    else:
        print('正常退出')


def main():
    while True:
        function_str = """
1.接收信息
2.发送信息
3.退出程序
        """
        print(function_str)
        choose = input('你想干啥')
        if choose == '1':
            udp_recv()
        elif choose == '2':
            udp_sendto()
        else:
            udp_socket.close()
            exit()


if __name__ == "__main__":
    main()

windows部分运行结果

linux部分


05.tcp应用

下载文件_client部分代码
import socket


def main():
    # 创建套接字
    tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 输入对应端口及ip地址
    address_ip = input("请输入服务器对应的端口及ip")
    address_port = int(input("请输入服务器对应的端口及ip"))
    # 连接
    tcp_socket.connect((address_ip, address_port))
    # 输入要发送的文件
    download = input('请输入要下载的文件名')
    # 发送文件名
    tcp_socket.send(download.encode('utf-8'))
    # 接收文件
    data = tcp_socket.recv(1024)
    # 将接收的文件写入
    with open("下载"+download, "wb") as file:
        file.write(data)


if __name__ == "__main__":
    main()
"""
TCP
UDP   最主要的区别是tcp更稳定
"""
下载文件_服务器部分代码
import socket


def main():
    # 创建套接字
    tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 绑定本地端口及套接字
    tcp_socket.bind(('192.168.239.131', 8080))
    # 设置链接数量
    tcp_socket.listen(1)
    # 等待响应
    new_tcp_socket, address = tcp_socket.accept()
    print(f'正在为客户端{address[0]},端口{address[1]}提供服务')
    # 打开对应的文件
    new_tcp_socket.send('请输入要下载的文件名'.encode('utf-8'))
    client_need = new_tcp_socket.recv(1024)
    file_name = client_need.decode('gbk')
    while client_need:
        try:
            with open(file_name, 'rb') as file:
                data = file.read()
            new_tcp_socket.send(data)
            print(f'该客户端下载了{file_name}')
        except:
            new_tcp_socket.send('没有找到该文件'.encode('utf-8'))
        # 打开对应的文件
        new_tcp_socket.send('请输入要下载的文件名'.encode('utf-8'))
        client_need = new_tcp_socket.recv(1024)
        file_name = client_need.decode('gbk')
    print('该服务已结束')
    new_tcp_socket.close()
    tcp_socket.close()


if __name__ == '__main__':
    main()

Windows运行服务器端

linux客户端


总结:第一次写博客排版以及对内容的讲解肯定有点问题的地方,希望各位指出,同时对于文章的内容可能有一些错误如果有发现的及时告知,我会更正本博客,同时由于时间比较急可能还有点东西需要加还有待更新。本知识通过学习黑马程序员课程收获而来,目前学完的还有多任务知识,待总结,所以最近可能发多任务,发完以后差不多就保持一礼拜一篇的速度。

未来的路很远很艰辛,愿各位smile每一天,相信终有一天收获自己的成功

Logo

更多推荐