网络编程

会有一股神秘感。 提交于 2019-11-27 22:10:06

1.基本概念

网络通信目的:

IP地址

目的:用来标记网络通信中的一台计算机

window查看ip地址: CMD窗口输入命令 ipconfig

IP地址的分类:

ip v4:
    每一个ip地址包括两部分:网络地址和主机地址
    常用ip地址:192:168:1~254.1~254

ip v6(正在发展)

单播:一对一
多播:一对多

端口:就是一个数字,标记进程,好比就是一个房子的门,是出入这间房子的必经之路

端口分类:知名端口 动态端口

端口是通过端口号来标记的,端口号只有整数,范围是从0到65535
知名端口:是众所周知的端口号,范围从0到1023,不能随便用
    80端口分配给HTTP服务
    21端口分配给FTP服务

动态端口:范围1023~65535,一般不固定分配某种服务,而是动态分配的,可以随便用

进程:是运行起来的程序。

socket(套接字,类似于插口,插排)

socket是网络通信必备的,如常见的网络通信工具,qq,微信

1.创建一个tcp sokect(tcp套接字)
import socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  
s.close()

2.创建一个udp socket(udp套接字)
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 
s.close() # 不用的时候,关闭套接字 
import socket
def main():
    # 创建一个udp套接字
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    
    udp_socket.sendto(b'hahaha',("192.168.11.189",8080)) #192.168.11.189本机ip地址
   
    # 关闭套接字
    udp_socket.close()

 if __name__ ==  "__main__":
        main()
        
'''
b'100' 表示字节类型 
'''      
=========================================================================================
import socket
def main():
    # 创建一个udp套接字
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    # 从键盘中获取数据
    send_data = input("请输入要发送的数据: ") 
    udp_socket.sendto(send_data.encode("utf-8"),("192.168.11.189",8080))# 发送数据 
    # 关闭套接字
    udp_socket.close()

 if __name__ ==  "__main__":
        main()
=========================================================================================
import socket
def main():
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    while True:#循环不间断发送数据
        send_data = input("请输入要发送的数据:")
        if send_data == "exit":
            break
        udp_socket.sendto(send_data.encode("utf-8"),(("192.168.11.189",8080)))# 发送数据
        udp_socket.close()

if __name__ == "__main__": 
    main()
接收数据
'''
要想接收数据,必须要有一个固定的端口
'''
import socket
# 创建套接字
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 绑定本地的相关信息,如果一个网络程序不绑定,系统就会随机分配 
local_addr = ('',7788) # ip地址和端口号,ip一般不写,表示本机的任何一个ip
udp_socket.bind(local_addr)

# 等待接收对方发送的数据
recv_data = udp_socket.recvfrom(1024) # 1024表示本次接收的最大字节数
# 显示接收到的数据
print(recv_data[0].decode("gbk"))
udp_socket.close()
import socket
def main():
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    # 绑定本地的相关信息,如果一个网络程序不绑定,系统就会随机分配 
    local_addr = ('',7788) # ip地址和端口号,ip一般不写,表示本机的任何一个ip
    udp_socket.bind(local_addr)
    # 等待接收对方发送的数据
    recv_data = udp_socket.recvfrom(1024) # 1024表示本次接收的最大字节数
    # 显示接收到的数据
    print(recv_data[0].decode("gbk")) # window 默认为"gbk"
    print(recv_data[1]) #显示发送方的地址信息
    udp_socket.close()

if __name__ == "__main__":
    main()
=========================================================================================# 循环接收数据
import socket
def main():
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    # 绑定本地的相关信息,如果一个网络程序不绑定,系统就会随机分配 
    local_addr = ('',7788) # ip地址和端口号,ip一般不写,表示本机的任何一个ip 
    udp_socket.bind(local_addr)
    # 等待接收对方发送的数据
    while True:
        recv_data = udp_socket.recvfrom(1024) # 1024表示本次接收的最大字节数
        print(recv_data[0].decode("gbk")) # window 默认为"gbk",# 显示接收到的数据
        print(recv_data[1]) # 打印发送方的地址信息
    udp_socket.close()

if __name__ == "__main__":
    main()
总结:

发送数据的流程: 接收数据的流程:


1、创建套接字 1、创建套接字

2、发送数据 2、绑定本地自己的信息(ip 和端口)

3、关闭 3、接收数据

​ 4、关闭


端口绑定

t同一台电脑 ip地址不相同

'''
单工:百分之一百只能走向一个方向 (如收音机)
半双工: 发送时不能接收,接收时不能发送 (如收音机)
全双工: 同一个时刻既可以发送也可以接收 (打电话)
'''
socket套接字是全双工
import socket
def main():
    ''''''
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    #获取对方的ip/port
    dest_ip = input("请输入对方的IP:")
    dest_port = int(input("请输入对方的port:"))
    #从键盘获取数据
    send_data = input("请输入要发送的数据:")
    udp_socket.sendto(send_data.encode("utf-8"),(dest_ip,dest_port))
    
    recv_data = udp_socket.recvfrom(1024) # 接收回送过来的数据
    print(recv_data)
    
    udp_socket.close()
    '''套接字是一个同时收发数据'''   
if __name = "__main__":
    main()
    
UDP聊天案列
import socket

def main():
    #创建套接字
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    udp_socket.bind(("",7788))
    # 循环循环来进行处理事情
    while True:
        dest_ip = (input("请输入对方的ip:"))
        dest_port = int(input("请输入对方port:"))
        send_data = input("请输入要发送的消息:")
        udp_socket.sendto(send_data.encode("utf-8"),(dest_ip,dest_port))
        
        # 接收并显示
        recv_data = udp_socket.recvfrom(1024)
        print(f'接收内容:{recv_data[0].decode("utf-8")}')
        print(f'对方ip地址:{str(recv_data[1])}')
        
if __name__ == "__main__":
    main()

TCP

TCP协议:传输控制协议(Transmission Control Protocol) 一种面向连接的,可靠的

UDP协议: 用户数据报协议

二者区别:

udp通信模型中,在通信开始之前,不需要建立相关的连接,只需要发送数据即可,类似于生活中的"写信"。(不安全)

tcp(打电话) :更稳定 可靠。TCP通信之前 必须 创建连接 数据传送 终止连接。

TCP比UDP稳定,应用更广泛。UDP很少用,通常用来发送数据,接收数据


TCP严格区分客户端和服务端

tcp客户端
import socket
def main():
    # 创建tcp的套接字
   tcp_client_socket = socket.socket(AF_INET,SOCK_STREAM)
    # 连接服务器
   server_ip = input("请输入要连接的服务器的IP:")
   server_port = int(input("请输入要连接的服务器的port:"))
   tcp_client_socket.connect((server_ip,server_port)) #输入参数元组
   # 提示用户输入数据
    send_data = input("请输入要发送的数据:")
   # 发送数据/接收数据
    tcp_socket.send(send_data.encode("utf-8"))
    # 关闭套接字
    tcp_socket.close()
       
if __name == "__main__":
    main()
tcp服务器
'''
socket创建一个套接字
bind绑定ip和port
listen使套接字变为可以被动连接
accept等待客户端的连接
recv/send接收发送数据
'''
import socket

def main():
    
    tcp_server_socket = socket.socket(AF_INET,SOCK_STREAM)
    tcp_server_socket.bind("",8080)
    # 让默认的套接字由主动变成被动
    tcp_server_socket.listen(128) 
    print('----1----')
    # 等待别人的电话到来(等待客户端的连接)
    new_client_socket,client_addr = tcp_server_socket.accept() # accept()返回的是元组  
    print('----2----')
    
    print(client_addr)
    # 接收客户端发送过来的请求
    recv_data = new_client_socket.recv(1024)
    print(recv_data)
    
    # 回送一部分数据给客户端
    new_client_socket.send("hahahaha...ok....".encode("utf-8"))
    
    # 关闭套接字
    new_client_socket.close()
    tcp_server_socket.close()
    
if __name__ == "__main__":
    main()
    
tcp 服务器(循环为多个客户端服务)
import socket
def main():
    tcp_server_socket = socket.socket(SOCK.AF_INET,sock.SOCK_STREAM)#创建套接字socket
    tcp_server_socket.bind(("",7000)) #绑定本地信息
    tcp_server_socket.listen(128) #让默认的套接字由主动变成被动 listen
    
    while True:
        
        print("等待一个新的客户端的到来")
        new_client_socket,client_addr = tcp_server_socket.accept() #等待客户端的连接accept() 
        print(f'一个新的客户端已经到来:{str(client_addr)}')
        recv_data = new_client_socket.recv(1024) #接收客户端发送过来的请求
        print(f'客户端发送过来的请求是:{recv_data.decode("utf-8")}')
     
        new_client_socket.send("hahaha...".encode("utf-8")) #回送一部分数据给客户端
        new_client_socket.close()  # 关闭套接字
       '''关闭accept返回的套接字 意味着 不会再为这个客户端服务'''
        print("已经服务完毕")
        
    tcp_server_socket.close()  
    '''如果将监听套接字关闭了,那么会导致 不能再次等待新客户的到来 ,即xxx.accept就会失败 不会有新的客户端到来 '''

if __name__ == "__main__":
    main()
tcp 服务端 (循环为多个客户端服务并且多次服务一个客户端)
import socket
def main():
    tcp_server_socket = socket.socket(SOCK.AF_INET,sock.SOCK_STREAM)#创建套接字socket
    tcp_server_socket.bind(("",7000)) #绑定本地信息
    tcp_server_socket.listen(128) #让默认的套接字由主动变成被动 listen
    
    while True: # 外层while True 循环为多个客户端服务
        
        print("等待一个新的客户端的到来")
        new_client_socket,client_addr = tcp_server_socket.accept() #等待客户端的连接accept() 
        print(f'一个新的客户端已经到来:{str(client_addr)}')
        
        while True: #内层 while True 循环多次为同一个客户端服务多次
            
            recv_data = new_client_socket.recv(1024) #接收客户端发送过来的请求
            print(f'客户端发送过来的请求是:{recv_data.decode("utf-8")}')
            '''
               若recv解堵塞,那么有两种方式:
               a.客户端发送过来的数据
               b.客户端调用close导致了
            ''' 
            if recv_data:
                new_client_socket.send("hhahhhh".encode("utf-8"))
            else:
                break
            new_client_socket.close()  # 关闭套接字
           '''关闭accept返回的套接字 意味着 不会再为这个客户端服务'''
            print("已经服务完毕")
        
    tcp_server_socket.close()  
    '''如果将监听套接字关闭了,那么会导致 不能再次等待新客户的到来 ,即xxx.accept就会失败 不会有新的客户端到来 '''

if __name__ == "__main__":
    main()
总结
1 tcp服务器一般情况下都需要绑定,否则客户端找不到这个服务器
2 tcp客户端一般不绑定,,因为是主动连接服务器,所以只需要确定好服务器的IP 、port 等信息就好了,本地客户端可以随机
3 tcp服务器中通过listen可以将socket创建出来的主动套接字变为被动的。这是作tcp服务器时必须要做的。
4 当客户端需要连接服务器时,就需要使用connect进行连接,UDP是不需要连接的而是直接发送的,但是tcp必须先连接,只有连接成功才能通信。
5 当一个tcp客户端连接服务器时,服务器端就会有一个1新的套接字,这个套接字用来标记这个客户端,单独为这个客户端服务。

6 listen 后的套接字是被动套接字,用来接收新的客户端的连接请求的,而accpet返回的新套接字是标记这个新客户端的

7 关闭listen后的套接字意味着被动套接字关闭了,会导致新的客户端不能够连接服务器,但是之前已经连接成功的客户端正常通信

8 关闭accept返回的套接字意味着这个客户端已经服务完毕
9 当客户端套接字调用close、服务器就会recv解堵塞,并且返回的长度为0.因此服务器可以通过返回数据的长度来区别客户端是否已经下线。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!