Socket是网络编程的一个抽象概念。通常我们用一个Socket表示“打开了一个网络链接”,而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可。
TCP和UDP的区别:
- (TCP)传输控制协议,是一种提供可靠数据传输的通用协议。
- (UDP)用户数据报协议,是一个面向无连接的协议。采用该协议不需要两个应用程序先建立连接。UDP协议不提供差错恢复,不能提供数据重传,因此该协议传输数据安全性差。
以上是书面内容
1、双方都是一种[网络传输协议]
2、TCP需要建立连接,而UDP不需要建立连接(无连接传输)
3、是否建立真实连接的特性,造成了双方可靠性的差距。
- TCP属于可靠的传输协议:因为传输前双方建立好了连接,相当于买卖双方建立好了交易合同,传输中一般不会出现意外,直到连接终止;
- UDP属于不可靠的传输协议:UDP的所谓连接相当于一种映射,UDP单方面的认为目标地址(端口)是可用的,从而进行收发数据,而实际上目标地址(端口)未必可用,所以传输数据不可靠
4、由于TCP需要建立真实的连接,所以需要消耗服务器的负载要大于UDP
tcp服务器
完成一个tcp服务器的功能,需要的流程如下:
- socket创建一个套接字
- bind绑定ip和port
- listen使套接字变为可以被动链接
- accept等待客户端的链接
- recv/send接收发送数据
客户端
大多数连接都是可靠的TCP连接。创建TCP连接时,主动发起连接的叫客户端,被动响应连接的叫服务器。
import socket
import time
# socket对象
clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('1......')
'''
连接服务器,
如果连接上,继续运行
连接不上,报错
'''
clientSocket.connect(('192.168.11.74',8888))
print('2......')
#关闭
clientSocket.close()
服务端
import socket
import time
# 买个手机
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 插卡
serverSocket.bind(('', 8888))
# 由飞行模式到接听模式
serverSocket.listen(10)
print('1......')
'''
clientAddr:连接的客户端的信息(ip,port)
'''
# 等待电话打入
newSocket, clientAddr = serverSocket.accept()
print('2......')
print(newSocket)
print(clientAddr)
# time.sleep(100)
# 关
newSocket.close() # 关闭之后,客户端也会被关闭
serverSocket.close() # 项目运行中服务器一直运行,不会关闭
tcp服务端发送和接收消息
import socket
import time
'''
serverSocket是用来接收新的客户端的
以后与这个连接的客户端的收发消息就不能用serverSocket了,
而是用返回来的新的newSocket
'''
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.bind(('', 8888))
serverSocket.listen(10)
newSocket, clientAddr = serverSocket.accept()
#发
sendData = input('>>')
newSocket.send(sendData.encode('gbk'))
#收
'''
此时的recv会导致阻塞。
一旦对应客户端断开了,不阻塞,并返回''的字符串
'''
recvData = newSocket.recv(1024)
print(recvData.decode('gbk'))
newSocket.close()
serverSocket.close()
客户端接受和发送消息
import socket
import time
clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientSocket.connect(('192.168.11.66',8888))
#发
sendData = input('>>')
clientSocket.send(sendData.encode('gbk'))
#收
recvData = clientSocket.recv(1024)
print(recvData.decode('gbk'))
clientSocket.close()
tcp服务器使用多线程接受多个客户端
import socket
import time
import threading
def socketState(newSocket,clientAddr):
while True:
recvData = newSocket.recv(1024)
recvData = recvData.decode('gbk')
if recvData == '':
print('客户端%s退出了...'%clientAddr[0])
newSocket.close()
break
else:
print('来自于%s:%s的消息(%s):%s'%(clientAddr[0],clientAddr[1],time.strftime('%Y-%m-%d %H:%M:%S'),recvData))
sendData = 'echo:%s'%recvData
newSocket.send(sendData.encode('gbk'))
def main():
#创建服务端socket对象
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.bind(('', 8888))
serverSocket.listen(10)
#循环,等待多个客户端连接
while True:
#等待客户端的连接,阻塞。连接后,继续运行
newSocket, clientAddr = serverSocket.accept()
#创建新的线程,执行与新客户端的交互
serverThread = threading.Thread(target=socketState, args=(newSocket,clientAddr))
serverThread.start()
# 这里不能关闭,多线程共享数据
#newSocket.close()
if __name__ == '__main__':
main()
服务端使用多进程接收多个客户端
import socket
import time
import multiprocessing
def socketState(newSocket,clientAddr):
while True:
recvData = newSocket.recv(1024)
recvData = recvData.decode('gbk')
if recvData == '':
print('客户端%s退出了...'%clientAddr[0])
newSocket.close()
break
else:
print('来自于%s:%s的消息(%s):%s'%(clientAddr[0],clientAddr[1],time.strftime('%Y-%m-%d %H:%M:%S'),recvData))
sendData = 'echo:%s'%recvData
newSocket.send(sendData.encode('gbk'))
def main():
#创建服务端socket对象
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.bind(('', 8888))
serverSocket.listen(10)
#循环,等待多个客户端连接
while True:
#等待客户端的连接,阻塞。连接后,继续运行
newSocket, clientAddr = serverSocket.accept()
#创建新的进程,执行与新客户端的交互
serverProcess = multiprocessing.Process(target=socketState, args=(newSocket,clientAddr))
serverProcess.start()
'''
这里要关闭。
子进程会单独分配与父进程相同的内容,地址不同(深拷贝)
'''
newSocket.close()
if __name__ == '__main__':
main()
总结:
用TCP协议进行Socket编程在Python中十分简单,对于客户端,要主动连接服务器的IP和指定端口,对于服务器,要首先监听指定端口,然后,对每一个新的连接,创建一个线程或进程来处理。通常,服务器程序会无限运行下去。
同一个端口,被一个Socket绑定了以后,就不能被别的Socket绑定了。