网络编程 ----tcp编程

网络编程

IP地址:网络中的唯一识别地址,好比人的身份证。
局域网的ip地址可以复用,不同的局域网内的ip地址可以相同,但是对于广域网来说,所有的ip地址都是唯一的。

IP地址分类

IPV4:目前最大的IP地址格式。255.255.255.255
IPV6:以后主流的IP地址格式。号称让地球上的每一粒沙子都有IP地址
查看IP地址的方式:windows:命令行 > ipconfig
                 linux:  终端 > ifconfig
查看网络详细信息:ping  www.baidu.com
访问ip地址也是可以访问网站的,除非对方禁止掉,或者它的ip地址比较特殊,需要加一些端口号。

端口

定义:应用程序之间的通信通道。
端口号的作用:区分不同的应用程序
分类:   知名端口:0-1023
        动态端口号:1024-65536(自己开发的时候用)

TCP

稳定的、可靠的、不会丢失数据的通信传输协议,需要对方应答之后才能开始通信。
可靠传输:
        1.面向连接
            通信双方必须先建立好连接才能进行数据的传输,数据传输完成后,双方必须断开此连接,以释放系统资源。
        2.可靠传输
            TCP 采用发送应答机制
            超时重传
            错误校验
            流量控制和阻塞管理

UDP

udp不稳定不可靠的通信协议,传输速度快,一般用于做广播。

socket(套接字)

作用:模块,只要是搞网络通信的,都要用这个模块。把我们的tcp、ip、端口号拿来使用。

总结

ip地址相当于每个电脑的详细路由地址,端口号相当于指定了哪个程序,TCP相当于通信双方之间的语言(就像人交流一样,用相同的语言才能听懂)

===================================================

TCP客户端的开发:

示例代码:
    import socket
if __name__ == '__main__':
    # 1.创建客户端套接字对象
    # AF_INET表示的是使用IPV4      SOCKET_STREAM表示的是使用TCP协议
    tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2.和服务端套接字建立连接
    # connect 参数只能有一个,而且必须是元组格式的
    tcp_client.connect(("192.168.88.133", 8082))
    # 3.发送数据
    send_date = input("请输入你想说的话:").encode("utf-8")
    tcp_client.send(send_date)
    # 4.接收数据
    recv_date = tcp_client.recv(1024).decode("utf-8")
    print("服务端:", recv_date)
    # 5.关闭客户端套接字
    tcp_client.close()

注意:读者在运行代码时建议百度下载网络调试助手调试看是否能够通信

windows编码要用"gbk",linux编码要用"utf-8"

===================================================

TCP服务端的开发

示例代码:

 import socket
if __name__ == '__main__':
    # 创建服务端端套接字对象
    tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 设置端口复用
    # SOL_SOCKET 安全级别:socket级别 
    # SO_REUSEPORT 是否设置端口重复使用  True 表示确认重复使用
    tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, True)
    # 绑定端口号
    # 这里和connect是一样的,bind里面的参数也必须是元组,""代表本机的任意一个ip地址都可以
    tcp_server.bind(("", 8087))
    # 设置监听的最大连接数为8
    tcp_server.listen(8)
    # 等待接受客户端的连接请求
    # 这里拆包得到的是一个新的套接字对象和一个客户端的ip和端口的元组,这个新的套接字是用来和客户端传输数据的,每连接一个客户端,就会产生一个新的套接字对象用来为那个客户端专门服务,直至结束通信并关闭套接字。
    new_tcp_server, client_port = tcp_server.accept()
    # 接收数据
    recv_date = new_tcp_server.recv(1024)
    print(f"收到的数据是:{recv_date.decode('utf-8')}")
    print("接收到的客户端地址为:ip: %s,端口号port: %d" % client_port)
    # 发送数据
    send_date = "连接成功,很高兴为您服务。".encode("utf-8")
    new_tcp_server.send(send_date)
    # 关闭套接字
    # 先关闭为每个客户端提供服务的套接字
    new_tcp_server.close()
    # 再关闭服务端的套接字
    tcp_server.close()

注意:端口复用一般用于学习测试用的,在企业里端口一般不用变化,而且企业级服务器一般是不关机的

以上就是tcp服务器开发的主要流程,每个步骤都有详细的说明,读者可根据源码和注释进行学习。读者不必去深究socket模块的底层原理,只需要懂如何使用就好了。

TCP注意点:

1.当 TCP 客户端程序想要和 TCP 服务端程序进行通信的时候必须要先建立连接
2.TCP 客户端程序一般不需要绑定端口号,因为客户端是主动发起建立连接的。
3.TCP 服务端程序必须绑定端口号,否则客户端找不到这个 TCP 服务端程序。
4.listen 后的套接字是被动套接字,只负责接收新的客户端的连接请求,不能收发消息。
5.当 TCP 客户端程序和 TCP 服务端程序连接成功后, TCP 服务器端程序会产生一个新的套接字,收发客户端消息使用该套接字。
6.关闭 accept 返回的套接字意味着和这个客户端已经通信完毕。
7.关闭 listen 后的套接字意味着服务端的套接字关闭了,会导致新的客户端不能连接服务端,但是之前已经接成功的客户端还能正常通信。(重点)原因:因为他们之间的通信是创建了一个新的套接字,不是用的服务器的那个套接字,所以关闭服务器的套接字不能中止
他们的通信
代码示例:
    new_tcp_server, client_port = tcp_server.accept()
    tcp_server.close()
    # 将关闭服务端的套接字放在accept方法后面
8.如何判断客户端是否下线:判断接收到的数据
                if len(recv_date) > 0:
                    用户在线要执行的代码
                else:
                    print("用户已下线")
                    break

===============================================================

TCP多任务编程

代码示例:

    import socket
    import threading


    def client_handler(new_tcp_server):
    """
    把跟客户端有关的代码都创建成一个线程函数
    """
        # 接收数据
        while True:
            recv_date = new_tcp_server.recv(1024)
            if len(recv_date) > 0:
                print(f"收到的数据是:{recv_date.decode('utf-8')}")
                # 发送数据
                send_date = "连接成功,很高兴为您服务。".encode("utf-8")
                new_tcp_server.send(send_date)
            else:
                print("客户端已经下线")
                # 关闭套接字
                new_tcp_server.close()
                break


    if __name__ == '__main__':
        # 创建服务端端套接字对象
        tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 设置端口复用
        tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, True)
        # 绑定端口号
        tcp_server.bind(("", 8080))
        # 设置监听的最大连接数为8
        tcp_server.listen(8)
        # 创建多线程,用while True 能建立未知个线程,有多少个客户端链接成功,就创建个多少个专门为该客户端服务的套接字,也创建多少个线程。
        while True:
            # 等待接受客户端的连接请求
            new_tcp_server, client_port = tcp_server.accept()
            ip, port = client_port
            print("接收到的客户端地址为:ip: %s,端口号port: %d" % (ip, port))
            client_hand = threading.Thread(target=client_handler, args=(new_tcp_server,))
            client_hand.setDaemon(True) #设置守护主线程,防止关闭服务器之后,已经建立的tcp链接还能继续通信
            client_hand.start()

因为udp传输不可靠,数据易丢失,用处不多,所以这里不做讲解,读者若想了解,请移步至:UDP编程“廖雪峰老师的教程”

你可能感兴趣的:(网络编程 ----tcp编程)