网络编程与TCP编程 理论基础

一.网络编程理论基础

1.网络

      网络,顾名思义就是通过点、线、面组成的一张连通全球的虚拟的大网,实现信息资源上的共享。

      最早期的网络,是用物理线路将多台计算机连接起来实现计算机之间特定的数据交互。这种方式一定程度上缓解了数据共享的需求。然而这种方式极为简陋,极大的限制了数据共享的范围和计算机共享的普遍适用性,越来越不能满足日益发展的计算机网络技术的需求。

      在这种迫切需求数据通信共享的情况下,计算机网络计数有了飞速的发展,为了在众多计算机中找到特定的计算机,Vint cerf在实验模拟阶段使用了32位标记的网络地址协议(即后来的IP地址)用来标识网络上唯一的一台计算机,为了能在一台计算机中找到特定的某个程序,将计算机中的每个和外界连接的数据程序设定了数据通信通道(即后来的端口)

      同一时间国际标准化组织ISO定义了经典的OSI/RM参考模型,极大的方便了人们在网络上进行数据通信传输,同时人们可以通过不同的协议进行数据的有效传播和共享

2.网络编程的模型

      每一个网络应用基本都由服务端和客户端组成,网络编程的模型也就是"客户端-服务器端"模型。那么什么是服务端什么又是客户端呢?见名知意,服务端负责管理某些资源,而客户端就是这些资源的需求者。就如同售货员跟顾客一样,售货员提供商品,客户从售货员这里获得他们需要的物品。

客户端-服务器端


3.网络协议

      什么是协议?协议呢,通俗的来讲,网络协议就是一种双方都知道的必须遵守的约定。就比如两个民族的人交流,但是你用苗语,他用瑶语,虽然各自都知道自己要表达的意思,但是对方听不懂啊,为了更加友好的交流,就有了这么一个约定,都用汉语中的普通话交流,这样就能消除各民族语言之间的差异导致的无效交流了,毕竟CCTV这个各民族都会看的频道都说的是普通话嘛,谁都会谁都能听得懂,何乐而不为呢?同样的,计算机之间的通信也是遵循不同层次的协议,来实现计算机的通信。为了把全世界的所有不同类型的计算机都连接起来,就必须规定一套全球通用的协议,为了实现这个目标,互联网协议簇就成为了通用协议标准。互联网协议包含了上百种协议,但是最重要的两个协议是TCP和IP协议,而我们通常把基于TCP和IP协议的所有协议统称为”TCP/IP协议(蔟)”。

      网络协议又是用来干什么的呢?你用两个不同主机之间需要进行通信,需要利用各种硬件(光纤,路由器,交换机等)实现物理连接组成局域网和广域网.这些网络中的主机如果需要进行通信,就需要遵守相同的约定,即协议.网络中的应用抽象成7层,各层都有对应的协议,这些协议有两种基本的功能即命名方法(确定通信的双方的身份)和传送机制(如何把信息传送过去).

七层模型


4.网络中的通信方式

      在网络中,如何将数据包发送给对方呢?socket套接字的出现解决了这一问题,通过套接字 socket 对象的连接,完成多种协议的网络程序服务端/客户端的开发和数据通信。它不是一种协议,而是对TCP/UDP等协议进行封装以后供程序调用的接口,代码中调用相应的接口,即可将数据发送给对方。这种编程方式叫做socket编程.客户端建立一个socket,服务端建立一个socket,二者建立连接后便可以进行通信,以TCP协议的socket为例,步骤如下:

1)服务端创建一个socket,并且需要指定相应的端口(端口为2字节),此时这个服务进程便于该端口绑定,监听端口的连接请求;

2)客户端创建一个socket,客户端的端口号一般由内核分配,

3)客户端的socket向某IP地址:端口的socket发送连接请求;

4)服务端的socket监听到连接请求后建立连接,此时两个socket便建立了可靠地TCP连接,可以进行通信;

5)通信结束后客户端关闭socket并向服务端发送关闭请求;

6)服务端受到关闭请求后关闭socket

socket是长连接,连接建立后可以多次通信,最后主动关闭连接.实际中可能长时间不通信socket也会断掉,此时需要自己实现心跳机制确保连接不断开;
      基本语法结构:
socket.socket(socket_family, socket_type, protocal=0)
socket_family:socket 地址家族,AF_UNIX/AF_LOCAL 或者 AF_INET
socket_type:socket 连接类型
面向连接的(SOCK_STREAM),面向无连接的(SOCK_DGRAME)
protocal:传输协议,一般不用设置,使用默认值进行自动匹配就好
      创建 TCP 协议的套接字 socket 对象:

tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

      创建 UDP 协议的套接字 socket 对象:

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

      socket套接字常用操作:

属性 描述
s.bind() 绑定(主机名称、端口)到一个套接字上
s.listen() 设置并启动TCP监听
s.accept() 等待客户端连接
s.connect() 连接到指定服务器
s.connect_ex() 连接指定服务器。如果出现错误返回信息
s.recv() 接收TCP消息
s.recv_into() 接收TCP消息到缓冲区
s.send() 发送TCP消息
s.sendall() 完整发送TCP消息
s.recvfrom() 接收UDP消息
s.recvfrom_info() 接收UDP消息到缓冲区
s.sendto() 发送UDP消息
s.shutdown() 关闭连接对象
s.close() 关闭套接字对象


二.TCP编程理论基础

1.三次握手与四次挥手

      TCP是一种面向连接的,可靠的、基于字节流的传输层通信协议,通过三次握手与四次挥手完成连接的可靠性。
三次握手:
第一次握手:客户端向服务器端发送连接请求包SYN(syn=j),等待服务器回应;

第二次握手:服务器端收到客户端连接请求包SYN(syn=j)后,将客户端的请求包SYN(syn=j)放入到自己的未连接队列,此时服务器需要发送两个包给客户端;
  (1)向客户端发送确认自己收到其连接请求的确认包ACK(ack=j+1),向客户端表明已知道了其连接请求
  (2)向客户端发送连接询问请求包SYN(syn=k),询问客户端是否已经准备好建立连接,进行数据通信;
  即在第二次握手时服务器向客户端发送ACK(ack=j+1)和SYN(syn=k)包,此时服务器进入SYN_RECV状态。

第三次握手:客户端收到服务器的ACK(ack=j+1)和SYN(syn=k)包后,知道了服务器同意建立连接,此时需要发送连接已建立的消息给服务器;
  向服务器发送连接建立的确认包ACK(ack=k+1),回应服务器的SYN(syn=k)告诉服务器,我们之间已经建立了连接,可以进行数据通信。
  ACK(ack=k+1)包发送完毕,服务器收到后,此时服务器与客户端进入ESTABLISHED状态,开始进行数据传送。

三次握手



四次挥手:
第一次挥手:主机A向主机B发送FIN包;A告诉B,我(A)发送给你(B)的数据大小是N,我发送完毕,请求断开A->B的连接。

第二次挥手:主机B收到了A发送的FIN包,并向主机A发送ACK包;B回答A,是的,我总共收到了你发给我N大小的数据,A->B的连接关闭。

第三次挥手:主机B向主机A发送FIN包;B告诉A,我(B)发送给你(A)的数据大小是M,我发送完毕,请求断开B->A的连接。
第四次挥手:主机A收到了B发送的FIN包,并向主机B发送ACK包;A回答B,是的,我收到了你发送给我的M大小的数据,B->A的连接关闭。

四次挥手

2.服务端的开发

服务端的编程操作步骤如下:
1)定义需要监听的主机 IP 和端口号
2)绑定 IP 地址和端口号到套接字对象
3)开始监听
4)等待连接
5)连接成功-开始数据通信
6) 断开连接

# -*- coding: utf-8 -*-

import socket,time

HOST = ''
PORT = 8081
ADDRESS = (HOST,PORT)
BUFFER = 1024

#创建服务端套接字
tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcp_server.bind(ADDRESS)
tcp_server.listen(10086)

while True:
    #等待客户端建立连接
    print('waitting')
    client_socket,client_address = tcp_server.accept()
    print("欢迎{}的光临".format(client_address))
    while True:
        #服务端发送消息
        info = input("server:")
        client_socket.send(info.encode('utf-8'))
        print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))

        #接收客户端消息
        msg = client_socket.recv(BUFFER)
        print("client{}:{}".format(client_address,msg.decode('utf-8')))
        print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
        print("☆" * 20)

        #客户端退出服务端等待状态
        if msg == b'bye':
            client_socket.close()
            break

tcp_server.close()

3.客户端的开发

客户端开发操作步骤如下:
1)创建 TCP 连接套接字对象
2)向指定的 IP 和 PORT 发起请求,请求连接
3)连接成功,进行数据收发操作
4)关闭连接,释放资源

# -*- coding: utf-8 -*-

import socket,time

TARGET_HOST = '192.168.209.1'
TARGRT_PORT = 8081
TARGET_ADDRESS = (TARGET_HOST,TARGRT_PORT)
BUFFER = 1024

#创建套接字对象,连接主机
tcp_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcp_client.connect(TARGET_ADDRESS)

while True:

    #接收服务端消息
    msg = tcp_client.recv(BUFFER)
    print("server:{}".format(msg.decode('utf-8')))
    print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))

    #客户端发送消息
    info = input("client:")
    tcp_client.send(info.encode('utf-8'))
    print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
    print("☆" * 20)

    #客户端关闭套接字退出
    if info == 'bye':
        tcp_client.close()
        break

print("客户端退出")

你可能感兴趣的:(网络编程与TCP编程 理论基础)