之前在编写四层发现的代码时都是使用TCP/UDP协议, 但是看了很多的代码都是用socket来完成的,所以就 来学习一下socket。
什么是socket
网络中的两台主机之间进行通信,本质上是主机中所 运行的进程之间的通信,两个进程如果需要进行通信 ,最基本的前提是每一个进程要有一个唯一的标识。
在本地进程通信中可以使用PID来唯一标识一个程, 但PID在 本地是唯一,可以用 "IP地+ 协议+端口号" 来组成唯一标识的网络进程,这就是socket。
无论使用何种网络协议,最本质上都是在进行数据 的收发,发和收,这两个动作就是socket处理数据 的主要方式。
socket的工作流程
socket 采用C/S 模式,分为服务端和客户端
服务端数据处理流程
创建socket -> 绑定到地址和端口 -> 等待连接 -> 开始通信-> 关闭连接
客户端数据处理流程
创建socket -> 等待连接 -> 开始通信-> 关闭连接
客户端没有绑定地址和端口,是由于客户端进程采用的是随机端口,当客户端要去连接目标时,会由系统自定分配一个端口号和自身ip地址去组合
socket_tcp_udp_client_service.py
#!/usr/bin/env python3
#coding=utf-8
import sys
import socket
import time
import os
import threading
ServerIp='192.168.1.1'
ServerPort=9999
def tcp_client_run():
global ServerIp
global ServerPort
print("tcp socket client connect to: ",ServerIp, ServerPort)
myServerPort=int(ServerPort)
#创建一个socket的类,socket.AF_INET指的是IPV4,SOCK_STREAM指的是TCP协议,UDP协议对应socket_DRAM
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#连接PC服务器的端口,参数是(IP/域名,端口)
ServerPort_=(ServerIp,myServerPort)
# connect_ex是connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
s.connect_ex(ServerPort_)
#接受服务器的消息,限制接受大小为1kb=1024b=128KB
while True:
try:
#接受消息,并打印,解码用utf-8
print("Local:OK?")
print(s.recv(1024).decode('utf-8'))
time.sleep(1)
#发送消息,注意用二进制的数据传输,因为发送的实际是一个数据流
data=(('Client'.encode('utf-8')))
s.send(data)
except:
break
print("Connection is closed by Server")
#定义一个接受和发送数据的函数,5次发送后即在服务器端强行关闭连接。
def tcplink(sock,addr):
global ServerIp
print("Accept the new connection from %s:%s"%addr)
sock.send(b"Welcome!Here is the Sever ")
n=int(5)
while n>0:
data=sock.recv(1024)
time.sleep(1)
sock.send(('Server==>I have heard you.{:s}:{:d},{:d} talks remaining\n'.format(addr[0],addr[1],n-1)).encode('utf-8'))
sock.send(('Server==>You said:{:s}\n'.format(data.decode('utf-8'))).encode('utf-8'))
n-=1
sock.close()
print('Connection from %s is close.'%addr[0])
def tcp_service_run():
global ServerIp
global ServerPort
print("socket tcp service connect to: ",ServerIp, ServerPort)
#创建socket类的实例,并绑定和监听,闲置最大连接数为2.
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((ServerIp,int(ServerPort)))
s.listen(2)
print('server is listening,waiting for connection......')
#创建一个新的进程来处理客户端的请求
while True :
sock,addr=s.accept()
#注意accept方法得到的是一个socket类和一个端口地址的元组。用print命令很容易验证。
print(sock,addr)
try:
t=threading.Thread(target=tcplink,args=(sock,addr))
tname=t.name
print('Now {:s} is running for connection from {:s}'.format(tname,addr[0]))
t.start()
except :
print("Server is block")
def udp_client_run():
global ServerIp
global ServerPort
print("udp socket client connect to: ",ServerIp, ServerPort)
ip_port=(ServerIp,int(ServerPort))
BUFSIZE=1024
udp_server_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
while True:
msg=input('input msg>>: ').strip()
if not msg:continue
udp_server_client.sendto(msg.encode('utf-8'),ip_port)
back_msg,addr=udp_server_client.recvfrom(BUFSIZE)
print(back_msg.decode('utf-8'),addr)
print("Connection is closed by client")
def udp_service_run():
global ServerIp
global ServerPort
print("udp socket service connect to: ",ServerIp, ServerPort)
ip_port=(ServerIp,int(ServerPort))
BUFSIZE=1024
udp_server_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
udp_server_client.bind(ip_port)
while True:
msg,addr=udp_server_client.recvfrom(BUFSIZE)
print(msg,addr)
udp_server_client.sendto(msg.upper(),addr)
print("Connection is closed by service")
if __name__ == '__main__':
if len(sys.argv) == 3 :
ServerIp=sys.argv[1]
ServerPort=sys.argv[2]
serviceType=input('is client or service?: ').strip()
protocolType=input('is tcp or udp?: ').strip()
if protocolType=='tcp':
if serviceType=='client':
tcp_client_run()
else:
tcp_service_run()
else:
if serviceType=='client':
udp_client_run()
else:
udp_service_run()
else:
print("Use: python3 tcp_client.py 192.168.1.1 9999")
客户端和服务端都执行 python3 tcp_client.py 192.168.1.1 9999来测试,选择是客户端还是服务器,tcp还是udp
之后可以正常通信。