如何正确理解套接字

版权声明:作者:人学物理死的早 出处:https://blog.csdn.net/weixin_39561473 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。 https://blog.csdn.net/weixin_39561473/article/details/86583713

一、认识套接字

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:开始监听,等待客户端连接

客户端实例:

from socket import *
#建立套接字,第二个参数是流式套接字 tcp专用
clientd_socket = socket(AF_INET,SOCK_STREAM)
#目标主机,也就是服务器的ip和端口
serverAddress = ('10.10.16.194',9999)
#主动和服务器发起链接
clientd_socket.connect(serverAddress)

data = input('请输入数据')
#发送数据
clientd_socket.send(data.encode('utf-8'))
#接受数据
re = clientd_socket.recv(128)
print(re.decode('utf-8'))

clientd_socket.close()
  • accept():响应客户端的请求

阻塞当前线程

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

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

服务端实例:

from  socket import *
server_socket = socket(AF_INET,SOCK_STREAM)

local_address = ('10.10.16.194',9999)
#绑定本机ip和端口,那么此程序就只接收此端口好的所有网络链接
server_socket.bind(local_address)

#限制接受5个客户端的数据
server_socket.listen(5)
#接受链接,如果没有链接那么处于阻塞状态。
#有链接的时候,accept会返回两个值,第一个是socket链接,第二个是远程地址
lianjie,remoteAddress = server_socket.accept()
re = lianjie.recv(128)
print(re.decode('utf-8'))
#发送数据
data = input('请输入发送内容')
lianjie.send(data.encode('utf-8'))

lianjie.close()   #server_socket中的其中一个链接
server_socket.close() #server_socket相当于一个大的容器

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

客户端:

服务端:

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

客户端:


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

服务端:

from  socket import *
server_socket = socket(AF_INET,SOCK_STREAM)
local_address = ('10.10.16.194',9999)
server_socket.bind(local_address)
server_socket.listen(5)
lianjie,remoteAddress = server_socket.accept()
while True:
    re = lianjie.recv(128)
    print(re.decode('utf-8'))
    data = input('请输入发送内容')
    lianjie.send(data.encode('utf-8'))
lianjie.close()
server_socket.close()

猜你喜欢

转载自blog.csdn.net/weixin_39561473/article/details/86583713