如何正确理解套接字

一、认识套接字

TCP用主机的IP地址加上主机上的端口号作为TCP连接的端点,这种端点就叫做套接字(socket)或插口。
套接字用(IP地址:端口号)表示。

它是网络通信过程中端点的抽象表示,包含进行网络通信必需的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。

 

套接字(socket)是一种通信机制,凭借这种机制,客户/服务器系统的开发工作既可以在本地单机上进行,也可以跨网络进行,Linux所提供的功能(如打印服 务,ftp等)通常都是通过套接字来进行通信的,套接字的创建和使用与管道是有区别的,因为套接字明确地将客户和服务器区分出来,套接字可以实现将多个客 户连接到一个服务器。

但是说了半天,还是理解不了什么是套接字,其实这是一个狗屎一样的翻译问题:

谷歌翻译中socket直译为插座,字典中关于socket的解释为:an electrical device receiving a plug or light bulb to make a connection。译为:接收插头或灯泡以进行连接的电气设备。用c/s模型图来更好的理解插座的意义:

服务器就像一个大插排,包含很多插座,客户端就是像一个插头,每一个线程代表一条电线,客户端将电线的插头插到服务器插排上对应的插座上,就可以开始通信了。

 

数据传输需要通过协议,而套接字就是给数据传输添加协议的。

 

二、套接字特性

1、套接字属性

套接字的特性由3个属性确定,他们是,域,类型和协议

域指定套接字通信中使用的网络介质,最常见的套接字域是AF_INET,它指的是Internet网络

2、套接字类型

一个套接字可能有多种不同的通信方式

流套接字,流套接字提供一个有序,可靠,双向节流的链接,流套接字由类型SOCK_STREAM指定,它是在AF_INET域中通过TCP/IP链接实现的,这就是套接字类型(其实就是通信方式)

与流套接字相反,由类型SOCK_DGRAM指定的数据报套接字不建立和维持一个连接,它对可以发送的数据长度有限制,数据报作为一个单独的网络消息被传输,它可能会丢失,复制或乱序

3、套接字协议

套接字协议,通常使用默认就可以了(也就是最后一个参数填0)

 

 

三、基于套接字的TCP网络编程

1、创建流程概述

  • socket创建一个套接字,SOCK_DGRAM是用在UDP上的,而SOCK_STREAM是用于TCP协议的。
  • bind绑定IP和port
  • listen使套接字变为可以被动链接
  • accept等待客户端的链接
  • close关闭资源

 

2、socket模块常用于TCP的方法

  • connect(address):连接远程计算机
  • send():发送数据
  • recv():接收数据
  • listen:开始监听,等待客户端连接

 

客户端实例:

  1.  
    from socket import *
  2.  
    #建立套接字,第二个参数是流式套接字 tcp专用
  3.  
    clientd_socket = socket(AF_INET,SOCK_STREAM)
  4.  
    #目标主机,也就是服务器的ip和端口
  5.  
    serverAddress = ('10.10.16.194',9999)
  6.  
    #主动和服务器发起链接
  7.  
    clientd_socket.connect(serverAddress)
  8.  
     
  9.  
    data = input('请输入数据')
  10.  
    #发送数据
  11.  
    clientd_socket.send(data.encode('utf-8'))
  12.  
    #接受数据
  13.  
    re = clientd_socket.recv(128)
  14.  
    print(re.decode('utf-8'))
  15.  
     
  16.  
    clientd_socket.close()
  • accept():响应客户端的请求

阻塞当前线程

如果没有计算机连接,一直等待

如果有计算机连接,响应客户端

 

服务端实例:

  1.  
    from socket import *
  2.  
    server_socket = socket(AF_INET,SOCK_STREAM)
  3.  
     
  4.  
    local_address = ('10.10.16.194',9999)
  5.  
    #绑定本机ip和端口,那么此程序就只接收此端口好的所有网络链接
  6.  
    server_socket.bind(local_address)
  7.  
     
  8.  
    #限制接受5个客户端的数据
  9.  
    server_socket.listen(5)
  10.  
    #接受链接,如果没有链接那么处于阻塞状态。
  11.  
    #有链接的时候,accept会返回两个值,第一个是socket链接,第二个是远程地址
  12.  
    lianjie,remoteAddress = server_socket.accept()
  13.  
    re = lianjie.recv(128)
  14.  
    print(re.decode('utf-8'))
  15.  
    #发送数据
  16.  
    data = input('请输入发送内容')
  17.  
    lianjie.send(data.encode('utf-8'))
  18.  
     
  19.  
    lianjie.close() #server_socket中的其中一个链接
  20.  
    server_socket.close() #server_socket相当于一个大的容器

 

先运行服务端,在运行客户端:结果

客户端:

服务端:

 

3、改进一下,让程序不会在一收一发后停止

客户端:

  1.  
     
  2.  
    from socket import *
  3.  
    clientd_socket = socket(AF_INET,SOCK_STREAM)
  4.  
    serverAddress = ('10.10.16.194',9999)
  5.  
    clientd_socket.connect(serverAddress)
  6.  
    while True:
  7.  
    data = input('请输入数据')
  8.  
    clientd_socket.send(data.encode('utf-8'))
  9.  
    re = clientd_socket.recv(128)
  10.  
    print(re.decode('utf-8'))

服务端:

  1.  
    from socket import *
  2.  
    server_socket = socket(AF_INET,SOCK_STREAM)
  3.  
    local_address = ('10.10.16.194',9999)
  4.  
    server_socket.bind(local_address)
  5.  
    server_socket.listen(5)
  6.  
    lianjie,remoteAddress = server_socket.accept()
  7.  
    while True:
  8.  
    re = lianjie.recv(128)
  9.  
    print(re.decode('utf-8'))
  10.  
    data = input('请输入发送内容')
  11.  
    lianjie.send(data.encode('utf-8'))
  12.  
    lianjie.close()
  13.  
    server_socket.close()
posted @ 2020-12-25 14:14  北极星!  阅读(979)  评论(2编辑  收藏  举报