1.使用udp发送接收数据步骤:
1.创建客户端套接字
2.发送/接收数据
3.关闭套接字
import socket
def main():
##1.创建udp套接字
##socket.AF_INET 表示IPv4协议 AF_INET6表示IPv6协议
##socket.SOCK_DGRAM 数据报套接字,只应用于udp协议
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
##2.准备接收方的地址
##元祖类型 ip是字符串类型 端口号是整型
dest_addr = ('192.168.113.111',8888)
##要发送的数据
send_data = '我是要发送的数据'
##3.发送数据
udp_socket.sendto(send_data.encode("utf-8"),dest_addr)
##4.等待接收方发送的数据 如果没有收到数据则会阻塞等待,直到收到数据
##接收到的数据是一个元祖(接收到的数据,发送方的ip和端口)
##1024 表示本次接收的最大字节数
recv_data.addr = udp_socket.recvfrom(1024)
##5.关闭套接字
udp_socket.close()
if __name__ == '__main__'
main()
编码的转换
str---->bytes:encode编码
bytes--->str:decode()编码
udp服务端绑定端口号:
1.创建socket套接字
2.绑定端口号
3.接收/发送数据
4.关闭套接字
import socket
def main():
##1.创建udp套接字
##socket.AF_INET 表示IPv4协议 AF_INET6表示IPv6协议
##socket.SOCK_DGRAM 数据报套接字,只应用于udp协议
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
##2.绑定端口
##元祖类型 ip一般不写 表示本机的任何的一个ip
local_addr = (",7777)
udp_socket.bind(local_addr)
##3.准备接收方的地址
##元祖类型 ip是字符串类型 端口号是整型
dest_addr = ("1992.168.113.111",8888)
##要发送的数据
send_data = "我是要发送的数据"
##4.发送数据
udp_socket.sendto(send_data.encode("utf-8"),dest_addr)
##5.等待接收方发送的数据 如果没有收到数据则会阻塞等待,直到收到数据
##接收到的数据是一个元祖(接收到的数据,发送方的ip和端口)
##1024 表示本次接收的最大字节数
recv_data.addr = udp_socket.recvfrom(1024)
##6.关闭套接字
udp_socket.close()
if __name__ == '__main__':
main()
注意点:绑定端口要在发送数据前绑定
2.TCP协议
tcp客户端的创建流程:
1.创建TCP的socket套接字
2.连接服务器
3.发送数据给服务器端
4.接收服务器端发送的消息
5.关闭套接字
import socket
def main():
##1.创建客户端的socket
##socket.AF_INET 表示IPv4协议 AF_INET6表示IPv6协议
##socket.SOCK_STREAM 流式套接字,只应用于TCP协议
client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
##2.构建目标地址
server_ip = input('请输入服务器端的IP地址:')
server_port = int(input("请输入服务器端的端口号:"))
##3.连接服务器
#参数:元祖类型 ip是字符串类型 端口号是整型
client_socket.connect((server_ip,server_port))
##要发送给服务器端的数据
send_data = '我是要发送给服务器端的数据'
##4.发送数据
client_socket.send(send_data.encode('gbk'))
##5.接收服务器端回复的数据,没有消息会阻塞
#1024表示接收的最大字节数
recv_date = client_socket.recv(1024)
print("接收到的数据是:",recv_data.decode('gbk'))
##6.关闭套接字
client_socket.close()
if __name__ == "__main__":
main()
TCP服务端的创建流程:
1.创建TCP服务端的socket
2.bing绑定ip地址和端口号
3.listen使套接字变为被动套接字
4.acceept 取出一个客户端的连接,用于服务
5.recv/send接收和发送数据
6.关闭套接字
import socket
def mian():
##1.创建tcp服务端的socket
server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
##2.绑定
server_socket.bind(("",8888))
##3.listen使用套接字变为被动套接字
server_socket.listen(128)
##4.如果有新的客户端来链接服务端,那么就产生一个新的套接字专门为这个客户端服务。
##client_socket 用来为这个客户端服务
##tcp_server_socket 就可以省下来专门等待其他新客户端的链接
client_socket,client_addr = server_socket.accept()
##5.接收客户端发来的消息
recv_data = client_socket.recv(1024)
print('接收到客户端%s的数据:%s'%(str(client_addr),recv_data.decode('gbk')))
##6.回复数据给客户端
client_socket.send("收到消息".encode('gbk'))
##7.关闭套接字
client_socket.close()
server_socket.close()
if __name__ == "__main__":
main()
注意点:
- tcp 服务器一般都需要绑定,否则客户端找不到服务器。
- tcp 客户端一般不绑定,因为是主动链接服务器,所以只要确定好服务器的 ip、port 等信息就好,本地客户端可以随机。
- tcp 服务器中通过 listen 可以将 socket 创建出来的主动套接字变为被动的,这是做 tcp 服务器时必须要做的。
- 当客户端需要链接服务器时,就需要使用 connect 进行链接,udp 是不需要链接的而是直接发送,但是 tcp 必须先链接,只有链接成功才能通信。
- 当一个 tcp 客户端连接服务器时,服务器端会有 1 个新的套接字,这个套接字用来标记这个客户端,单独为这个客户端服务。
- listen 后的套接字是被动套接字,用来接收新的客户端的连接请求的,而 accept 返回的新套接字是标识这个新客户端的。
- 关闭 listen 后的套接字意味着被动套接字关闭了,会导致新的客户端不能够链接服务器,但是之前已经链接成功的客户端正常通信。
- 关闭 accept 返回的套接字意味着这个客户端已经服务完毕。
- 当客户端的套接字调用 close 后,服务器端会 recv 解阻塞,并且返回的长度为 0,因此服务器可以通过返回数据的长度来区别客户端是否已经下线;同理 当服务器断开 tcp 连接的时候 客户端同样也会收到 0 字节数据。
问1:怎么实现强行关闭客户端和服务器之间的连接?
在 socket 通信过程中不断循环检测一个全局变量(开关标记变量),一旦标记变量变为关闭,则 调
用 socket 的 close 方法,循环结束,从而达到关闭连接的目的。
问2:简述 TCP 和 UDP 的区别以及优缺点?
UDP 是面向无连接的通讯协议,UDP 数据包括目的端口号和源端口号信息。
优点:UDP 速度快、操作简单、要求系统资源较少,由于通讯不需要连接,可以实现广播发送
缺点:UDP 传送数据前并不与对方建立连接,对接收到的数据也不发送确认信号,发送端不知道数
据是否会正确接收,也不重复发送,不可靠。
TCP 是面向连接的通讯协议,通过三次握手建立连接,通讯完成时四次挥手
优点:TCP 在数据传递时,有确认、窗口、重传、阻塞等控制机制,能保证数据正确性,较为可靠。
缺点:TCP 相对于 UDP 速度慢一点,要求系统资源较多。