socket编程之TCP编程
socket是网络编程的一个抽象概念.通常我们用Socket表示"打开了一个网络连接",而打开一个Socket需要知道目标计算机的ip 地址和端口号,再指定协议即可.
在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
客户端/服务端架构
即C/S架构,包括
1.硬件C/S架构(打印机)
2.软件C/S架构(web服务)
客户端(c端)
- 大多数连接是可靠的TCP连接 ,创建TCP连接时,主动发起连接的叫客户端,被动响应连接的叫服务器.
举个栗子,我们把socket的过程比喻为一个打电话的过程,创建一个基于TCP链接的Socket:
import socket#导入socket模块
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#创建一个socket(拿一个电话)
phone.connect(("127.0.0.1",8080))#建立连接(拨电话)
其中,AF_INET表示指定ipv4协议,如果要更加先进的ipv6 ,可以指定 AF_INET6.目前ipv4还是主流. SOCK_STREAM指定指定面向流的TCP协议,这样一个Socket对象就创建成功.
其中("127.0.0.1",8080),前者是是服务器的ip,也可以用域名代替,后者是服务器端口号,作为服务器,ip和端口都应该是固定的.
注意("127.0.0.1",8080)是一个元祖.
建立TCP连接后,我们就可以向服务器发送请求,要求返回.
phone.send(msg.encode("utf-8"))#发送数据(对服务端说话)
TCP连接创建的是双向通道,双方都可以互相发数据.
data= phone.recv(1024)#接收服务端数据(听服务端的话)
print(data.decode("utf-8"))#显示出来
接收数据时,用recv(max)方法.其中括号指定一次最多接收的字节数.
当我们接收完数据后,调用close()方法关闭Socket,这样,一次完整的网络通信就结束了:
phone.close()#关闭连接(挂电话)
服务器(s端)
和客户端编程相比,服务器编程就要复杂一些。服务器进程首先要绑定一个端口并监听来自客户端的连接.所以服务器会打开固定端口监听,每一个客户端连接就创建该Socket连接.由于服务器会有大量来自客户端的连接,所以,服务器要能够区分一个Socket连接是和哪个客户端绑定的。一个Socket依赖4项:服务器地址、服务器端口、客户端地址、客户端端口来唯一确定一个Socket。
首先,创建一个基于IPv4和TCP协议的Socket:
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#同上,建立socket
然后,我们要绑定监听的地址和端口.端口号需要预先指定
phone.bind(("127.0.0.1",8080))#监听端口
phone.listen(5)#开始监听(5代表传入的参数指定等待连接的最大数量)
接下来,服务端程序用一个死循环来接收客户端的连接,accept()会等待并返回一个客户端的连接
while True:
conn,addr=phone.accept()#建立连接
然后,服务端程序用一个死循环开始接受客户端的数据,并返回数据
while True:
conn,addr=phone.accept()#建立连接
while True:
try:#建立异常处理机制,当客户端断开连接时,直接退出本层接收数据的循环,返回建立连接的循环
data=conn.recv(1024)#接收客户端数据
if not data:break#消息为空则重复循环
print("客户端发来的消息",data.decode("utf-8"))#打印客户端发来的数据
conn.send("好几把炫酷!".encode("utf-8"))#返回数据给客户端
except Exception:
break
conn.close()#关闭本次连接
我们从头到尾来一遍:
#服务端
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(("127.0.0.1",8080))
phone.listen(5)
print("starting")
while True:
conn,addr=phone.accept()
while True:
try:
data=conn.recv(1024)
if not data:break
print("客户端发来的消息",data.decode("utf-8"))
conn.send("好几把炫酷!".encode("utf-8"))
except Exception:
break
conn.close()
phone.close()
#客户端
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(("127.0.0.1",8080))
while True:
msg=input(">>>")
if not msg:continue
if msg=="quit":break
phone.send(msg.encode("utf-8"))
data= phone.recv(1024)
print(data.decode("utf-8"))
phone.close()
小结
用TCP协议进行Socket编程在python中十分简单,对于客户端,要主动连接服务端的ip和指定端口,对于服务端,则是监听指定端口.