一:Socket简介
- 套接字起源于20世纪70年代加利福尼亚大学伯克利分校版本的Unix,即人们所说的BSD Unix。因此,有时人们也把套接字称为“伯克利套接字"或"BSD套接字”。一开始,套接字被设计用在同 -台主机上多个应用程序之间的通讯
- BSD Socket接口是TCP/IP网络的API
- 在Linux,Unix和Windows均实现这个接口.BSD Socket的是目前开发网络应用主要接口.绝大部分网络应用均可Socket来开发
- 一个Socket队列是IP应用的基本单位.两个机器通讯相当于两个机器的两个Socket互相通讯的过程
- Socket 的本意是插座.每一个激活的socket可以看成是一个跟本地某个IP端口绑定的IP包队列
- 接口设计者最先是将接口放在Unix操作系统里面的。因此一个激活的Socket被设计成特殊的I/O文件, Socket也是一种文件描述符。 .因此操作类似对一个普通文件操作
- 套接字有两种(或者称为有两个种族),分别是基于文件型的和基于网络型的
基于文件类型的套接字家族
套接字家族的名字: AF_ _UNIX
unix-切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信
基于网络类型的套接字家族
套接字家族的名字: AF_ INET
(还有AF_ INET6被用于ipv6,还有一些其他的地址家族, 不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF INET是使用最广泛的-个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_ INET)
二:Socket基本函数
1、创建套接字
socket(socket.AF_INET,socket.SOCK_STREAM)
- socket.AF_INET:表示是基于网络的套接字家族,因而可以允许在远程 主机之间通信
- socket.SOCK_STREAM:表示流式模块,基于tcp协议,这样会提供按顺序的,可靠,双向,面向连接的比特流
2、设置端口重用
setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
比如,当我们把程序关闭了,但是操作系统还没有释放端口,再次启动就会报端口被占用的错误,使用setsockopt就解决这种情况
3、绑定
bind((‘127.0.0.1’,8000))
里面一定要是一个tuple类型,绑定ip,端口,ip是部署服务端的ip,如果是127.0.0.1,就表示服务端和客户端要在一台服务器上,端口0-65535,0-1024是操作系统使用,1024后的端口是应用程序使用
4、侦听
listen()
在某个端口上.侦听
5、accept ()
accept () listen侦听后,有客户端进来来调用,如果一直没有客户端来,就会阻塞在这里
6、connect ()
connect((‘127.0.0.1’,8000)) 联接远程某个Socket,里面也要一个tuple类型,ip和端口都填的是服务端的ip和端口
connect函数是客户端用来同服务端连接的
7、发送数据
send(msg.encode(“utf-8”)) 发送数据,需要把字符串转换为bytes
8、接收数据
recv(1024) 接收的数据 ,单位:bytes 这里表示最大接收1024个bytes
Socket 编程模型
- Socket当前编程模型一般都是C/S结构.即相互通信的网络程序中,一方称为客户程序(client),另一方称为服务程序(server)
- C/S结构中,客户端向服务器发送请求,服务器作出响应.象常见的浏览器/web服务器,FTP客户端/FTP服务器. 就是典型的C/S结构
- 一个服务器可以同时接受多个客户端请求
- 在socket编程中,服务器和客户端的编程流程有一些不同
socket编程的流程图
服务端流程:创建套接口(socket)→绑定套接口(bind)→设置套接口为监听模式,进入被动接受连接请求状态(listen) →接受请求(accept),建立连接(socket)→读/写数据(recv,send)→终止连接(close)
客户端流程:创建套接口(socket)→与远程服务程序连接(connect)→写/读数据(send/recv)→终止连接 (close)
代码实现
本例子实现是循环接收客户端,只能一个一个连接客户端,还不能并发
1、服务端代码,文件名server.py
#--coding:utf-8--
import socket
'''
socket.AF_INET:表示是基于网络的套接字家族
socket.SOCK_STREAM:表示流式模块,基于tcp协议
'''
#创建套接字
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#绑定ip,端口,ip是部署服务端的ip,如果是127.0.0.1,就表示服务端和客户端要在一台服务器上,端口0-65535,0-1024是操作系统使用,1024后的端口是应用程序使用
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #设置端口重用,比如端口已经关闭了但是操作系统还没有释放,会提示端口占用
server.bind(('0.0.0.0',8000))
#监听
server.listen()
print('staring....')
while True: #连接循环
conn , addr = server.accept()
print(addr)
while True: #通信循环
try:
data = conn.recv(1024) #1、单位:bytes 2、最大接收1024个bytes
if not data:break #适用于linux操作系统,如果客户端断开了连接,如果不处理在linux系统上,客户端断开后服务端就会进入的无限循环
print('客户端的数据:',data.decode('utf8'))
conn.send(data.upper()) #服务端接收到客户端的数据后,变成大写再返回给客户端
except ConnectionResetError: #适用于windows系统,如果客户端断开连接,在windows系统就会报ConnectionResetError的错误
break
conn.close()
server.close()
2、客户端代码,文件名称client.py
import socket
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#发起连接,服务端的ip和端口
client.connect(('127.0.0.1',8000))
while True:
msg = input(">>: ").strip() #去掉空格
if not msg:continue #如果发的是空就进入下一次循环,如果不处理,当客户端发送一个空字符后服务端就会阻塞在recv处
client.send(msg.encode("utf-8")) #将字符串转换为bytes
data = client.recv(1024)
print(data.decode("utf8"))
client.close()