我的Python_Socket网络编程

本文深入讲解Socket编程原理,包括TCP/IP、UDP协议的使用,如何创建服务器与客户端进行数据交互,以及高级应用如SSH和FTP式的通信。涵盖SocketServer并发处理、MD5校验和多用户FTP程序开发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、Socket语法及相关

在这里插入图片描述

socket
	tcp/ip	send	recv
	udp
family address(地址簇):
	AF.INET					#ipv4
	AF.INET6				#ipv6
	AF.UNIX					#本地地址,一般用不到
socket protocal type(协议类型):
	sock.SOCK_STREAM		#tcp/ip(默认)
	sock.SOCK_DGRAM			#数据报式socket,	for udp
服务端:
	server = socket.socket(AF_INET,socket.SOCK_STREAM,)			#一个实例
	server.bind(('localhost',9999))								#监听哪个地址,哪个端口
	server.listen()												#开始listen
	while True:										#加一个循环,让客户端断开之后,服务端接收新的客户端链接
		conn, addr = server.accept()				#每接收一个链接,生成一个客户端实例赋值给conn,addr是那个地址
		while True:
			print("new conn",addr)
			data = conn.recv(1024)					#接收数据(接收的大小)赋值给data,####最好是不超过8192(8K)
			###conn.recv默认是阻塞的,客户端一断开,conn.recv收到的数据就是空数据,将会进入死循环,So,加个判断
			if not data:
				barak								#如果数据为空,将跳出当前conn.recv,接收新的客户端连接
			print(data)
			conn.send(data.upper(())				#将数据变成大写返回给客户端

客户端:
	client = socket.socket()						#实例化一个
	client.connect('serverip',9999)					#服务端的地址和端口
	client.send(data)								#发送数据
	client.send(data)								#可发送多条
	client.recv(data)								#收取数据

2、socket概念

socket本质上就是在2台网络互通的电脑之间,架设一个通道,两台电脑通过这个通道来实现数据的互相传递。 
我们知道网络 通信 都 是基于 ip+port 方能定位到目标的具体机器上的具体服务,操作系统有0-65535个端口,每个端口都可以独立
对外提供服务,如果 把一个公司比做一台电脑 ,那公司的总机号码就相当于ip地址, 每个员工的分机号就相当于端口, 你想找公司
某个人,必须 先打电话到总机,然后再转分机 。
2.1、简单的实现一下socket
###客户端
#-*- coding:utf-8 -*-

import socket

client = socket.socket()                     #声明socket类型,同时生成socket连接对象
client.connect(('localhost',6969))


# s=bytes("Hello World",encoding='utf-8')
# client.send(s)
# client.send(b"Hello World")

while True:
    msg = input(">>:").strip()

    client.send(msg.encode("utf-8"))
    data = client.recv(1024)
    print("recv",data.decode())

client.close()

###服务端
import socket

server = socket.socket()
server.bind(('localhost',6969))     #绑定要监听的端口
server.listen()                     #监听端口

print("开始等电话")

while True:
    conn, addr = server.accept()  # 等电话进来
    # conn是客户端连过来在服务器端为其生成的一个链接实例
    # print(conn,addr)
    print("电话来了")

    while True:
        data = conn.recv(1024)
        print("recv:",data.decode())
        if not data:
            print("client is lost...")
            break
        conn.send(data.upper())
server.close()
2.2、实现一个socket相互通信的ssh式的交互
  • 服务端
#-*- coding:utf-8 -*-
# Author: li Shang

import socket,os,time

server = socket.socket()
server.bind(('0.0.0.0',9999))
server.listen()

while True:										#为了循环接收,客户端挂掉一个,服务端继续的等待别的
    conn,addr = server.accept()
    print("new conn:",addr)

    while True:									#循环地接收一个连接发过来的数据
        print("开始等待指令")
        data = conn.recv(1024)
        if not data:
            print("客户端已断开")
            break
        print("执行指令:",data)
        cmd_res = os.popen(data.decode()).read()	#接收字符串,执行结果也是字符串
        print("send brfore")
        if len(cmd_res) == 0:
            cmd_res = "sorry"

        conn.send(str(len(cmd_res.encode("utf-8"))).encode("utf-8"))
        # time.sleep(0.5)                       ###分开两个send,防止粘包,这种方式太low,换成下面的方式
        client_ack = conn.recv(1024)            #wait client to 确认
        print("准备好了吗?客户端:",client_ack.decode())
        conn.send(cmd_res.encode("utf-8"))
        print("send down")

server.close()
  • 客户端
#-*- coding:utf-8 -*-
# Author: li Shang

import socket

client = socket.socket()
client.connect(('localhost',9999))

while True:
    cmd = input(">>:").strip()
    if len(cmd) == 0:continue

    client.send(cmd.encode(encoding='utf-8'))
    cmd_res_size = client.recv(1024)            		#接收命令结果的长度
    print("大小为:",cmd_res_size)
    client.send("准备好接收了,发吧".encode("utf-8"))		#接收到了长度之后响应给服务端

    received_size = 0
    received_data = b''
    while received_size < int(cmd_res_size.decode()):	#实际接收的小于总数,就一直接收

        data = client.recv(1024)
        received_size += len(data)              		#每次收到的可能小于1024,所以必须用len()判断
        # print(data.decode("utf-8"))
        print(received_size)
        received_data += data
    else:
        print("接收完了...",received_size)
        print(received_data.decode("utf-8"))			#最后接收完毕,统一输出

client.close()
2.3、终极版(验证MD5):实现一个socket相互通信的FTP式的交互
(用再次与client交互一次来防止粘包)
  • 服务端
#-*- coding:utf-8 -*-
# Author: li Shang

import socket,os
import hashlib

server = socket.socket()
server.bind(('0.0.0.0',9999))
server.listen()

while True:
    conn,addr = server.accept()
    print("new conn:",addr)

    while True:
        print("开始等待指令")
        data = conn.recv(1024)
        if not data:
            print("客户端已断开")
            break

        cmd,filename = data.decode().split()
        print(filename)
        if os.path.isfile(filename):
            f = open(filename,"rb")
            m = hashlib.md5()
            file_size = os.stat(filename).st_size
            conn.send(str(file_size).encode())          #发送文件大小给client
            conn.recv(1024)                             #等待client响应
            for line in f:
                m.update(line)
                conn.send(line)
            f.close()
            client_ack = conn.recv(1024)				#防止粘包,MD5值也发送过去,等待客户端再次确认
            print("准备好了吗?客户端:",client_ack.decode())
            conn.send(m.hexdigest().encode())           #然后再发送 MD5 值给客户端
            print("file md5:",m.hexdigest())
server.close()
  • 客户端
#-*- coding:utf-8 -*-
# Author: li Shang

import socket
import hashlib

client = socket.socket()
client.connect(('10.10.1.19',9999))

while True:
    cmd = input(">>:").strip()
    if len(cmd) == 0: continue
    if cmd.startswith("get"):
        client.send(cmd.encode())
        server_response = client.recv(1024)					#接收server端发来的文件大小
        print("server_response:",server_response)

        client.send(b"reday to recv file")
        file_total_size = int(server_response.decode())
        received_size = 0

        filename = cmd.split()[1]
        f = open(filename + ".new","wb")
        m = hashlib.md5()

        while received_size < file_total_size:				#接收到的大小比总大小小,就一直接收
            data = client.recv(1024)						#接收数据
            received_size += len(data)						#计算接收的文件的大小
            m.update(data)
            f.write(data)									#把接收的内容写进新文件
            print(file_total_size,received_size)
        else:												#到这就全部接收完了
            new_file_md5 = m.hexdigest()					#本地文件的MD5print("file recv down")
            f.close()

        client.send("准备好接收了,发吧".encode("utf-8"))		#给server端发确认消息,让那边发MD5值过来
        server_file_md5 = client.recv(1024)					#接收到的server端文件的MD5print("client_file_md5:",new_file_md5)
        print("server_file_md5:",server_file_md5)

client.close()
2.4、终极终极版(验证MD5):实现一个socket相互通信的FTP式的交互
(服务端不改动,在client端设置最后一次仅接收剩下的数据来防止粘包)
  • 服务端
#-*- coding:utf-8 -*-
# Author: li Shang

import socket,os,time
import hashlib

server = socket.socket()
server.bind(('0.0.0.0',9999))
server.listen()

while True:
    conn,addr = server.accept()
    print("new conn:",addr)

    while True:
        print("开始等待指令")
        data = conn.recv(1024)
        if not data:
            print("客户端已断开")
            break

        cmd,filename = data.decode().split()
        print(filename)
        if os.path.isfile(filename):
            f = open(filename,"rb")
            m = hashlib.md5()
            file_size = os.stat(filename).st_size
            conn.send(str(file_size).encode())          #发送文件大小给client
            conn.recv(1024)                             #等待client响应
            for line in f:
                m.update(line)
                conn.send(line)
            f.close()
           #client_ack = conn.recv(1024)
           #print("准备好了吗?客户端:",client_ack.decode())
            conn.send(m.hexdigest().encode())           #send md5

            print("file md5:",m.hexdigest())
server.close()
  • 客户端
#-*- coding:utf-8 -*-
# Author: li Shang

import socket
import hashlib

client = socket.socket()
client.connect(('10.10.1.19',9999))

while True:
    cmd = input(">>:").strip()
    if len(cmd) == 0: continue
    if cmd.startswith("get"):
        client.send(cmd.encode())
        server_response = client.recv(1024)
        print("server_response:",server_response)

        client.send(b"reday to recv file")
        file_total_size = int(server_response.decode())
        received_size = 0

        filename = cmd.split()[1]
        f = open(filename + ".new","wb")
        m = hashlib.md5()

        while received_size < file_total_size:

            if file_total_size - received_size > 1024:      #要收不止一次
                size = 1024
            else:
                size = file_total_size - received_size
                print("最后一次收:",size)

            data = client.recv(size)
            received_size += len(data)
            m.update(data)
            f.write(data)
            print(file_total_size,received_size)
        else:
            new_file_md5 = m.hexdigest()
            print("file recv down")
            f.close()

        server_file_md5 = client.recv(1024)
        print("client_file_md5:",new_file_md5,type(new_file_md5))
        print("server_file_md5:",server_file_md5,type(server_file_md5))
        if str(server_file_md5,"utf-8") == new_file_md5:
            print("本地文件与server端的一致")
        else:
            print("本地文件与server端的一致,请检查")

client.close()

3、SocketServer(可以支持并发处理)

class socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)
class socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)
server.handle_request()								#只处理一个请求
serve_forever()										#处理多个请求,永远执行
  • 服务端
import socketserver

class MyTCPHandler(socketserver.BaseRequestHandler):		#定义一个类,继承socketserver.BaseRequestHandler
   """
   The request handler class for our server.

   It is instantiated once per connection to the server, and must
   override the handle() method to implement communication to the
   client.
   """

   def handle(self):										#要重写handle功能
       while True:											#可以持续接收客户端发的信息
           try:												#与下面你的except配合使用抓住错误
               # self.request is the TCP socket connected to the client
               self.data = self.request.recv(1024).strip()
               print("{} wrote:".format(self.client_address[0]))
               print(self.data)
               # if not self.data:         					#客户端断了,这是原来的用法,这里不用该方法
               #     print("client is down")
               #     break
               # just send back the same data, but upper-cased
               self.request.send(self.data.upper())
           except ConnectionResetError as e:				#与上面的try配合使用,抓住错误
               print("客户端断开了",e)
               break

if __name__ == "__main__":
   HOST, PORT = "localhost", 9999

   # Create the server, binding to localhost on port 9999
   server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)

   # Activate the server; this will keep running until you
   # interrupt the program with Ctrl-C
   server.serve_forever()
  • 客户端
import socket

client = socket.socket()                     #声明socket类型,同时生成socket连接对象
#client.connect(('10.10.1.19',9999))
client.connect(('localhost',9999))

while True:									#可以不断地发送数据
   msg = input(">>:").strip()	
   if len(msg) == 0: continue

   client.send(msg.encode("utf-8"))
   data = client.recv(1024)
   print("recv:",data.decode())

client.close()

而服务端只需要将
server = socketserver.TCPServer((HOST, PORT), MyTCPHandler) 换成
server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler) 就可以支持多并发了

4、开发一个支持多用户在线的FTP程序

  • 服务端
import socketserver
import json,os

class MyTCPHandler(socketserver.BaseRequestHandler):
   """
   The request handler class for our server.

   It is instantiated once per connection to the server, and must
   override the handle() method to implement communication to the
   client.
   """

   def put(self,*args):
       '''接收客户端文件'''
       cmd_dic = args[0]
       filename = cmd_dic["filename"]
       filesize = cmd_dic["filesize"]
       if os.path.isfile(filename):
           f= open(filename + ".new","wb")
       else:
           f = open(filename,"wb")

       self.request.send(b"200 ok")
       received_size = 0
       while received_size < filesize:
           data = self.request.recv(1024)
           f.write(data)
           received_size += len(data)
       else:
           print("file [%s] has uploaded" % filename)

   def handle(self):
       while True:
           try:
               # self.request is the TCP socket connected to the client
               self.data = self.request.recv(1024).strip()
               print("{} wrote:".format(self.client_address[0]))
               print(self.data)
               cmd_dic = json.loads(self.data.decode())
               action = cmd_dic["action"]
               if hasattr(self,action):
                   func = getattr(self,action)
                   func(cmd_dic)

           except ConnectionResetError as e:
               print("客户端断开了",e)
               break

if __name__ == "__main__":
   HOST, PORT = "localhost",9999

   # Create the server, binding to localhost on port 9999
   server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)

   # Activate the server; this will keep running until you
   # interrupt the program with Ctrl-C
   server.serve_forever()
  • 客户端
import socket
import os
import json

class FtpClient(object):
   def __init__(self):
       self.client = socket.socket()

   def help(self):
       msg = '''
       ls
       pwd
       cd   ../..
       get filename
       put filename
       '''
       print(msg)

   def connect(self,ip,port):
       self.client.connect((ip,port))

   def interactive(self):
       while True:
           cmd = input(">>>:").strip()
           if len(cmd) ==0: continue
           cmd_str = cmd.split()[0]
           if hasattr(self,"cmd_%s" % cmd_str):
               func = getattr(self,"cmd_%s" % cmd_str)
               func(cmd)
           else:
               self.help()

   def cmd_put(self,*args):
       cmd_split = args[0].split()
       if len(cmd_split) > 1:
           filename = cmd_split[1]
           if os.path.isfile(filename):
               filesize = os.stat(filename).st_size
               msg_dic = {
                   "action":'put',
                   "filename":filename,
                   "filesize":filesize
               }
               self.client.send(json.dumps(msg_dic).encode("utf-8"))
               server_response = self.client.recv(1024)
               print(server_response)
               f = open(filename,'rb')
               for line in f:
                   self.client.send(line)
               else:
                   print("文件传送完毕")

           else:
               print(filename ,"is not exist")

   def cmd_get(self):
       pass

ftp = FtpClient()
ftp.connect("localhost",9999)
ftp.interactive()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值