网络编程

一、网络编程

二、实现网络通讯的条件

  1、物理连接介质

  2、需要统一通讯标准

    OSI七层协议

  3、TCP建立连接的三次握手和四次挥手

三、什么是socket

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,

对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。

也有人将socket说成ip+port,ip是用来标识互联网中的一台主机的位置,而port是用来标识这台机器上的一个应用程序,ip地址是配置到网卡上的,
而port是应用程序开启的,ip与port的绑定就标识了互联网中独一无二的一个应用程序 而程序的pid是同一台机器上不同进程或者线程的标识

  socket 套接字

  是介于应用层和传输层之间的封装了 网络层 数据层 物理成 可以直接调用socket接口 帮我们实现通讯

五、解决TCP的粘包问题

该模块可以把一个类型,如数字,转成固定长度的byte

1 服务端 

同过导入 import Struct 模块

  制作报头

  发送报头

  发送字典

  发送真实信息

客户端f

  接收报头

  解析报头 获取head_size 获取字典长度 =struct(''i", head_dic)[0]  

  获取真实数据的字典

  head_bytes = json.loads(head_bytes.decode('utf-8'))

  # 获取的字典的大小的key  文件名和文件的大小

  # 进行文件的操作

  打开文件的 ‘wb’

  while recv_size < fiel_size :

    data = conn/client .recv(1024)

    #别忘了写入文件的方法

    # f.write(data)

    recv_size += len(data)

  

六、基于socket 上传和下载电影

  1、基于Socket大文件传输

  客户上传电影

客户端上传电影
import socket
import os
import json
import struct

#
client = socket.socket()
#
# # 建立与服务端的链接
client.connect(('127.0.0.1', 8080))
#
# # 通讯循环
while True:
    # 获取电影列表
    Movie_path = r'F:day29视频'
    movie_list = os.listdir(Movie_path)
    for index, movie in enumerate(movie_list,1):
        # 0,1,2,3  1 2 3 4
        print(index, movie)
    choice = input('输入电影的编号:').strip()
    if choice.isdigit():
        choice = int(choice)-1 # 0 1 2 3
        # len() 4          0  4 v  0 1 2 3
        if choice in range(0,len(movie_list)):
            file_name = movie_list[choice]
            # 拼接电影文件的路径
            movie_path = os.path.join(Movie_path,file_name)

            # 获取每一步电影文件大小
            file_size = os.path.getsize(movie_path)
            # 产生一个字典
            file_title = '精彩电影100部'

            my_dic = {
                'file_name': file_name,
                'file_size': file_size,
                'file_title': file_title,
                'other': '待续'
            }
            # 序列化字典
            json_dic = json.dumps(my_dic)
            # 转成二进制字典
            json_bytes = json_dic.encode('utf-8')
            # 制作字典报头

            head = struct.pack('i', len(json_bytes))
            # 发送报头
            client.send(head)
            # 发送二进制字典
            client.send(json_bytes)

            # 发送真实数据
            with open(movie_path, 'rb')as f:
                for line in f:
                    client.send(line)

        else:
            print('序号不在范围内')

    else:
        print('请输入数字')

  服务端保存电影

# 从服务端接收文件
import struct
import json


import socket
server = socket.socket()

# 接收电影
server.bind(('127.0.0.1', 8080))
# 设置半链接池
server.listen(5)
# 链接通讯
while True:
    # 等待链接

    conn, addr = server.accept()  # 等待链接
        # 通讯循环

    while True:
        try:  # 捕获文件
            # 开始接收信息
            # 接收报头
            head_dic = conn.recv(4)
            # 解析报头 获取大小
            head_size = struct.unpack('i',head_dic)[0]
            # 接收字典数据
            head_bytes = conn.recv(head_size)
            # 反序列化获取真实字典
            json_dic = json.loads(head_bytes.decode('utf-8'))
            print(json_dic)
            # {'file_name': '精彩电影100部',
            # 'file_size': 50835588, 'other': '待续'}
            file_name = json_dic.get('file_name')
            file_size = json_dic.get('file_size')

            recv_size = 0
            with open(file_name, 'wb')as f:
                while recv_size < file_size:
                    data = conn.recv(1024)
                    f.write(data)
                    recv_size += len(data)
                # print(recv_size.decode('utf-8'))
                print('上传成功%s' % file_name)

        except ConnectionRefusedError as e:
            print(e)
            break
    conn.close()

七、TCP 和UDP的区别 

  1.TCP和UDP 的特点

  



1 有无连接:
TCP面向连接协议, 必须建立双向通道 传输数据的可靠性 eg:打电话 相互传输数据)
Web浏览器;电子邮件、文件传输程序。
——UDP是无连接服务,数据不可靠 eg: 发短信 不需要回复

 

2. 传输方式:>>>(粘包的问题)
   TCP的特点是介于流式协议 会将内容比较小和 时间间隔较短的 一次性发送 (产生粘包的问题)
 ——UDP是基于数据报传输自带报头 不会产生粘包的问题
传输效率高(发送前时延小),一对一、一对多、多对一、多对多、面向报文,尽最大努力服务,无拥塞控制。
使用UDP的应用:域名系统 (DNS);视频流;IP语音(VoIP)。

3.传输效率:
TCP 需要建立双向通道 传输效率低
--UDP 无连接服务 传输效率个高

 UDP的特点


1.udp协议客户端允许发空
2.udp协议不会粘包
3.udp协议服务端不存在的情况下,客户端照样不会报错?
4.udp协议支持并发

  

八、实现UDP 简易版QQ通(并发)

  服务端

# 服务端

import socket

server = socket.socket(type=socket.SOCK_DGRAM)

server.bind(('127.0.0.1', 8080))

while True:
    # 通讯
    # 接受信息
    data , addr = server.recvfrom(1024)
    print(data.decode('utf-8'))

    # 发送信息
    cmd = input('>>>:').encode('utf-8')
    server.sendto(cmd, addr)

    # 记得发送对方的地址

服务端1

#  客户端
import socket

# 获取对像的ip 地址
client = socket.socket(type=socket.SOCK_DGRAM)

server_addrs = ('127.0.0.1', 8080)

while True:
    # 发送信息
    msg = input('输入的信息:')
    msg = '来自客户端1的消息:%s' % msg
    client.sendto(msg.encode('utf-8'), server_addrs)
    # 接收信息
    data, addr = client.recvfrom(1024)
    print(data.decode('utf-8'))

客户端2

#  客户端
import socket

# 获取对像的ip 地址
client = socket.socket(type=socket.SOCK_DGRAM)

server_addrs = ('127.0.0.1', 8080)

while True:
    # 发送信息
    msg = input('输入的信息:')
    msg = '来自客户端2的消息:%s' % msg
    client.sendto(msg.encode('utf-8'), server_addrs)
    # 接收信息
    data, addr = client.recvfrom(1024)
    print(data.decode('utf-8'))

客户端3

#  客户端
import socket

# 获取对像的ip 地址
client = socket.socket(type=socket.SOCK_DGRAM)

server_addrs = ('127.0.0.1', 8080)

while True:
    # 发送信息
    msg = input('输入的信息:')
    msg = '来自客户端3的消息:%s' % msg
    client.sendto(msg.encode('utf-8'), server_addrs)
    # 接收信息
    data, addr = client.recvfrom(1024)
    print(data.decode('utf-8'))

七、如何实现TCP的并发

  1、Socketserve模块的运用

  客服端

# 基于TCP如何 实现并发

# 发送消息给服务端
import socket
client = socket.socket()
client.connect(('127.0.0.1', 8080))

while True:
    msg = input('输入信息:').strip()
    # 发送信息
    client.send(msg.encode('utf-8'))

    data = client.recv(1024)
    print(data.decode('utf-8'))


# 基于TCP如何 实现并发

# 发送消息给服务端
import socket
client = socket.socket()
client.connect(('127.0.0.1', 8080))

while True:
    msg = input('输入信息:').strip()
    # 发送信息
    client.send(msg.encode('utf-8'))

    data = client.recv(1024)
    print(data.decode('utf-8'))



# 基于TCP如何 实现并发

# 发送消息给服务端
import socket
client = socket.socket()
client.connect(('127.0.0.1', 8080))

while True:
    msg = input('输入信息:').strip()
    # 发送信息
    client.send(msg.encode('utf-8'))

    data = client.recv(1024)
    print(data.decode('utf-8'))
可以同时发送信息 服务端 并发量

  服务端

# 基于的socketserver 实现并发

import socketserver
# class TCPServer(BaseServer):


class Myserver(socketserver.BaseRequestHandler):
    def handle(self):
        while True:
            data = self.request.recv(1024)
            print(data.decode('utf-8'))
            print(self.client_address)  # 客户端的地址
            self.request.send(data.upper())  # 发送信息

            # HSHSH  客户端发送过来的信息
            # ('127.0.0.1', 14657)
            # TTT
            # ('127.0.0.1', 14659)
            # YYYY
            # ('127.0.0.1', 14660)
            # UUU
            # ('127.0.0.1', 14661)
            # OOO
            # ('127.0.0.1', 14663)

if __name__ == '__main__':
    server = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), Myserver)  # 创建一个基于TCP的server对象
    server.serve_forever()  # 启动该服务对对象

  2、UDP基于Sockserver实现并发

UDP服务端

# UDP实现的并发

import socketserver


# 继承一个类
class Myserver(socketserver.BaseRequestHandler):

    def handle(self):
        while True:
            data, sock = self.request
            print(data.decode('utf-8'))
            print(self.client_address)
            # 发送信息
            # msg = input('输入信息:').encode('utf-8')
            sock.sendto(data, self.client_address)


if __name__ == '__main__':
    # 产生一个TCP 对象
    server = socketserver.ThreadingUDPServer(('127.0.0.1', 8080), Myserver)
    # 启动改对象
    server.serve_forever()

多个客户端

# UDP的并发实现

import socket
# 产生一个对象
import time

client = socket.socket(type=socket.SOCK_DGRAM)

# 需要获取服务端的通信地址‘
server_addrs = ('127.0.0.1',8080)

# 开始通讯
while True:
    # 发送信息
    client.sendto(b'hello baby ', server_addrs)

    # 接收信息
    data, addr = client.recvfrom(1024)
    print(data.decode('utf-8'))
    print(addr)
    time.sleep(1)

 客户端2

# UDP的并发实现

import socket
# 产生一个对象
import time

client = socket.socket(type=socket.SOCK_DGRAM)

# 需要获取服务端的通信地址‘
server_addrs = ('127.0.0.1',8080)

# 开始通讯
while True:
    # 发送信息
    client.sendto(b'hello baby ba', server_addrs)

    # 接收信息
    data, addr = client.recvfrom(1024)
    print(data.decode('utf-8'))
    print(addr)
    time.sleep(1)

客户端

# UDP的并发实现

import socket
# 产生一个对象
import time

client = socket.socket(type=socket.SOCK_DGRAM)

# 需要获取服务端的通信地址‘
server_addrs = ('127.0.0.1',8080)

# 开始通讯
while True:
    # 发送信息
    client.sendto(b'hello', server_addrs)

    # 接收信息
    data, addr = client.recvfrom(1024)
    print(data.decode('utf-8'))
    print(addr)
    time.sleep(1)

八、异常处理(异常捕获)

  1、 常见异常

# try:
#     name
#     l = [1,2,3]
#     l[111]
#     d = {'name':'jason'}
#     d['password']
# except NameError:
#     print('NameError')
# except IndexError:
#     print('indexerror')
# except KeyError:
#     print('keyerror')
"""
错误发生之后  会立刻停止代码的运行
执行except语句 比对错误类型
"""

# try:
#     # name
#     # l = [1,2,3]
#     # l[111]
#     d = {'name':'jason'}
#     d['password']
#     # Exception
# except BaseException:  # 万能异常  所有的异常类型都被捕获
#     print('老子天下无敌')





# try:
#     # name
#     l = [1,2,3]
#     l[111]
#     # d = {'name':'jason'}
#     # d['password']
# except Exception:  # 万能异常  所有的异常类型都被捕获
#     print('老子天下无敌')
# else:
#     print('被检测的代码没有任何的异常发生 才会走else')
# finally:
#     print('无论被检测的代码有没有异常发生 都会在代码运行完毕之后执行我')


# 主动抛异常
# if 'egon' == 'DSB':
#     pass
# else:
#     raise TypeError('尽说大实话')
# 关键字raise就是主动抛出异常


# l = [1,2,3]
# assert len(l) < 0  # 断言  预言
# 猜某个数据的状态 猜对了 不影响代码执行 正常走
# 猜错了  直接报错

# 自定义异常
#9 自定义异常
class MyError(BaseException):
     def __init__(self,msg):
         super().__init__()
         self.msg=msg
     def __str__(self):
         return '<dfsdf%ssdfsdaf>' %self.msg

raise MyError('我自己定义的异常')  # 主动抛出异常其实就是将异常类的对象打印出来,会走__str__方法

补充如果 端口号 已被使用 already use 

#加入一条socket配置,重用ip和端口

server=socket(AF_INET,SOCK_STREAM)
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
server.bind(('127.0.0.1',8080))
原文地址:https://www.cnblogs.com/mofujin/p/11324102.html