python socket recv超时_学Python划重点七 网络编程(使用TCP Socket实现QQ聊天)

前言: 在学校两个月都没有时间更博客,现在放假回家把原来准备好的给补上。

客户端服务器(Client Server, C/S) 结构网络是一种主从结构网络。服务器一般处于等待状态,如果有客户端请求,服务器响应请求,建立连接提供服务。服务器是被动的,客户端是主动的。

一、知识点总结

v2-ace33f1bf5289066c74befdcdd9f07ee_b.jpg

1. 创建TCP Socket

socket 模块提供了一个socket() 函数可以创建多种形式的socket 对象。 语法如下:socket(family, type[,protocol])

#  定义套接字 s
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

各参数的意义如下: family : 地址系列。默认为AF_INET (2 ,socket 模块中的常量),对应于IPV4 ;AF_UNIX ,对应于Unix 的进程间通信;AF_INET6 ,对应于IPV6 。 type : socket 类型。默认为SOCK_STREAM ,对应于TCP 流套接字;SOCK_DGRAM ,对应于UDP 数据报套接字;SOCK_RAW ,对应于raw 套接字。 protocol 指明所要接收的协议类型,通常为0 或者不填。

2. TCP Socket 服务器编程方法

sock.bind(address) : 绑定地址和端口,address 是包含主机名(或IP 地址)和端口的二元组对象; sock.listen(backlog) : 监听端口,backlog 是最大连接数,backlog 默认值是1 。 sock.accept() : 等待客户端连接, 连接成功返回二元组对象(conn, address) ,其中conn 是新的socket对象,可以用来接收和发送数据,address 是客户端的地址。

s.bind(("127.0.0.1", 8888)) # 绑定IP和端口(参数为二元组),就是寻址
 s.listen(5) #  因为是TCP,所有要监听端口
 self.conn,self.addess=s.accept() # 等待客户端连接(参数为最大连接数),返回一个二元组(新的socket对象+客户端地址)
 data =self.conn.recv(1024) # 接受1024字节序列数据(这个函数阻塞,直到接受到数据)

3 .客户端编程socket 方法

socket.connect(address) :连接服务器

s.connect(("127.0.0.1", 8888))

socket ,address 是包含主机名(或IP 地址)和端口的二元组对象。

4 .服务器和客户端编程socket 共用方法

socket.recv(buffsize) : 接收TCP Socket 数据, 该方法返回字节序列对象。 参数buffsize 指定一次接收的最大字节数,因此如果要接收的数据量大于buffsize ,则需要多次调用该方法进行接收。 socket.send(bytes) : 发送TCP Socket 数据,将bytes 数据 发送到远程Socket ,返回成功发送的字节数。如果要发送的数据量很大,则需要多次调用该方法发送数据。 socket.sendall(bytes) : 发送TCP Socket 数据,将bytes 数据 发送到远程Socket ,如果发送成功返回None ,如果失败则抛出异常。与socket.send(bytes) 不同的是,该方法连续发送数据,直到发送完所有数据或发生异常。 socket.settimeout(timeout) : 设置Socket 超时时间,timeout 是一个浮点数,单位是秒,值为None 则表示永远不会超时。一般超时时间应在刚创建Socket 时设置。 socket.close() : 关闭Socket ,该方法虽然可以释放资源, 但不一定立即关闭连接 ,如果要及时关闭连接,需要在调用该 方 法之前调用shutdown() 方法。请注意,Python 中的Socket 对象是可以被垃圾回收的,当socket 对象被垃圾回收,则socket 对象会自动关闭,但建议显式地调用close() 方法关闭socket 对象。

---

二、实现QQ聊天 (未使用多线程)

未使用多线程会出现阻塞,只能一发一收的进行,不能多发多收进行!

v2-7d4b26b3bc9132fa4797d829c67b8bb2_b.gif

==服务器端:==

# 案列使用TCP连接
# 这是服务器端

import socket
import wx
#  定义套接字 s
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

# 定义窗口类
class MyFrame(wx.Frame):
    # 初始化这里就是生成界面,然后绑定了按钮事件,其他没了
    def __init__(self):
        super().__init__(parent=None,size=(350,250),title="QQ聊天:服务器")
        self.Center()
        panel=wx.Panel(self)
        self.text = wx.TextCtrl(parent=panel, id=-1, style=wx.TE_MULTILINE,size=(100,150))
        startbutton = wx.Button(parent=panel, id=1, label="开启服务器")
        self.inputtext = wx.TextCtrl(parent=panel, id=-1)
        button=wx.Button(parent=panel,id=2,label="发送")
        # 绑定按钮事件
        self.Bind(wx.EVT_BUTTON, self.Talk, id=1)
        self.Bind(wx.EVT_BUTTON,self.on_button,id=2)
        box1=wx.BoxSizer()
        box1.Add(startbutton, 1, flag=wx.ALL | wx.EXPAND, border=10)
        box1.Add(self.inputtext,1,flag=wx.ALL|wx.EXPAND,border=10)
        box1.Add(button,1,flag=wx.ALL|wx.EXPAND,border=10)
        mainbox=wx.BoxSizer(wx.VERTICAL)
        mainbox.Add(self.text,flag=wx.EXPAND)
        mainbox.Add(box1, flag=wx.EXPAND)
        panel.SetSizer(mainbox)

    # 开启服务器端函数
    def Talk(self,event):
        s.bind(("127.0.0.1", 8888)) # 绑定IP和端口(参数为二元组),就是寻址
        s.listen(5) #  因为是TCP,所有要监听端口
        print("服务器启动·····")
        self.conn,self.addess=s.accept() # 等待客户端连接(参数为最大连接数),返回一个二元组(新的socket对象+客户端地址)
        data =self.conn.recv(1024) # 接受1024字节序列数据(这个函数阻塞,直到接受到数据)
        if len(data) != 0: # 将接受的数据写入文本纪录框中
            self.text.LabelText += "客户端:" + data.decode() + "rn"

    # 发送信息给客户端函数
    def on_button(self,event):
        msg=self.inputtext.GetValue() # 获取要发送的文本
        self.conn.send(msg.encode()) # 给客户端发送信息
        self.text.LabelText+="服务器:"+msg+"rn" # 将发送信息写入纪录文本框

        data = self.conn.recv(1024) # 等待接收客户端信息
        if len(data) != 0:
            self.text.LabelText +="客户端:"+data.decode()+"rn" # 将发送信息写入纪录文本框

# 应用程序
class App(wx.App):
    def OnInit(self):
        frame=MyFrame()
        frame.Show()
        return True
    def OnExit(self):
        s.close() # 关闭socket对象
        return 0

# 进入main函数运行:循环
if __name__=="__main__":
    app=App()
    app.MainLoop()

==客户端:==

# 案列使用TCP连接
# 这是客户端
import socket
import wx

#  定义套接字 s
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

# 定义窗口类
class MyFrame(wx.Frame):
    # 初始化这里就是生成界面,然后绑定了按钮事件,其他没了
    def __init__(self):
        super().__init__(parent=None, size=(350, 250), title="QQ聊天:客户端")
        self.Center()
        panel = wx.Panel(self)
        self.text = wx.TextCtrl(parent=panel, id=-1, style=wx.TE_MULTILINE, size=(100, 150))
        startbutton = wx.Button(parent=panel, id=1, label="连接服务器")
        self.inputtext = wx.TextCtrl(parent=panel, id=-1)
        button = wx.Button(parent=panel, id=2, label="发送")
        self.Bind(wx.EVT_BUTTON, self.Talk, id=1)
        self.Bind(wx.EVT_BUTTON, self.on_button, id=2)
        box1 = wx.BoxSizer()
        box1.Add(startbutton, 1, flag=wx.ALL | wx.EXPAND, border=10)
        box1.Add(self.inputtext, 1, flag=wx.ALL | wx.EXPAND, border=10)
        box1.Add(button, 1, flag=wx.ALL | wx.EXPAND, border=10)
        mainbox = wx.BoxSizer(wx.VERTICAL)
        mainbox.Add(self.text, flag=wx.EXPAND)
        mainbox.Add(box1, flag=wx.EXPAND)
        panel.SetSizer(mainbox)

    # 连接服务器函数
    def Talk(self, event):
        s.connect(("127.0.0.1", 8888))
        return

    # 发送信息给服务器端
    def on_button(self, event):
        msg = self.inputtext.GetValue()# 获取要发送的文本
        s.send(msg.encode())# 给服务器端发送信息
        self.text.LabelText += "客户端:" + msg + "rn"# 将发送信息写入纪录文本框

        data = s.recv(1024)# 等待接收服务器端信息
        if len(data) != 0:
            self.text.LabelText += "服务器:" + data.decode() + "rn"# 将发送信息写入纪录文本框

class App(wx.App):
    def OnInit(self):
        frame = MyFrame()
        frame.Show()
        return True

if __name__=="__main__":
    app=App()
    app.MainLoop()

----

三、实现QQ聊天 (使用多线程)

v2-d6abeca9b29af83853eda8cbaf091f65_b.gif

==服务器端:==

# 这个聊天案例使用了 多线程
# 案列使用TCP连接
# 这是服务器端

import socket
import wx
import threading
import time


#  定义套接字 s
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

# 定义窗口类
class MyFrame(wx.Frame):
    # 初始化这里就是生成界面,然后绑定了按钮事件,其他没了
    def __init__(self):
        super().__init__(parent=None,size=(350,250),title="QQ聊天:服务器")
        self.Center()
        panel=wx.Panel(self)
        self.text = wx.TextCtrl(parent=panel, id=-1, style=wx.TE_MULTILINE,size=(100,150))
        startbutton = wx.Button(parent=panel, id=1, label="开启服务器")
        self.inputtext = wx.TextCtrl(parent=panel, id=-1)
        button=wx.Button(parent=panel,id=2,label="发送")
        # 绑定按钮事件
        self.Bind(wx.EVT_BUTTON, self.Talk, id=1)
        self.Bind(wx.EVT_BUTTON,self.on_button,id=2)
        box1=wx.BoxSizer()
        box1.Add(startbutton, 1, flag=wx.ALL | wx.EXPAND, border=10)
        box1.Add(self.inputtext,1,flag=wx.ALL|wx.EXPAND,border=10)
        box1.Add(button,1,flag=wx.ALL|wx.EXPAND,border=10)
        mainbox=wx.BoxSizer(wx.VERTICAL)
        mainbox.Add(self.text,flag=wx.EXPAND)
        mainbox.Add(box1, flag=wx.EXPAND)
        panel.SetSizer(mainbox)

    # 开启服务器端函数
    def Talk(self,event):
        s.bind(("127.0.0.1", 8888)) # 绑定IP和端口(参数为二元组),就是寻址
        s.listen(5) #  因为是TCP,所有要监听端口
        print("服务器启动·····")
        self.conn, self.addess = s.accept()  # 等待客户端连接(参数为最大连接数),返回一个二元组(新的socket对象+客户端地址)
        threadQQ=threading.Thread(target=self.thread_body,name="Srever")
        threadQQ.start()


    def thread_body(self):
        while True:
            data = self.conn.recv(1024)  # 接受1024字节序列数据(这个函数阻塞,直到接受到数据)
            if len(data) != 0:  # 将接受的数据写入文本纪录框中
                self.text.LabelText += "客户端:" + data.decode() + "rn"
            time.sleep(1)


    # 发送信息给客户端函数
    def on_button(self,event):
        msg=self.inputtext.GetValue() # 获取要发送的文本
        self.conn.send(msg.encode()) # 给客户端发送信息
        self.text.LabelText+="服务器:"+msg+"rn" # 将发送信息写入纪录文本框

# 应用程序
class App(wx.App):
    def OnInit(self):
        frame=MyFrame()
        frame.Show()
        return True
    def OnExit(self):
        s.close() # 关闭socket对象
        return 0

# 进入main函数运行:循环
if __name__=="__main__":
    app=App()
    app.MainLoop()

==客户端:==

# 这个聊天案例使用了 多线程
# 案列使用TCP连接
# 这是客户端
import socket
import wx
import threading
import time

#  定义套接字 s
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

# 定义窗口类
class MyFrame(wx.Frame):
    # 初始化这里就是生成界面,然后绑定了按钮事件,其他没了
    def __init__(self):
        super().__init__(parent=None, size=(350, 250), title="QQ聊天:客户端")
        self.Center()
        panel = wx.Panel(self)
        self.text = wx.TextCtrl(parent=panel, id=-1, style=wx.TE_MULTILINE, size=(100, 150))
        startbutton = wx.Button(parent=panel, id=1, label="连接服务器")
        self.inputtext = wx.TextCtrl(parent=panel, id=-1)
        button = wx.Button(parent=panel, id=2, label="发送")
        self.Bind(wx.EVT_BUTTON, self.Talk, id=1)
        self.Bind(wx.EVT_BUTTON, self.on_button, id=2)
        box1 = wx.BoxSizer()
        box1.Add(startbutton, 1, flag=wx.ALL | wx.EXPAND, border=10)
        box1.Add(self.inputtext, 1, flag=wx.ALL | wx.EXPAND, border=10)
        box1.Add(button, 1, flag=wx.ALL | wx.EXPAND, border=10)
        mainbox = wx.BoxSizer(wx.VERTICAL)
        mainbox.Add(self.text, flag=wx.EXPAND)
        mainbox.Add(box1, flag=wx.EXPAND)
        panel.SetSizer(mainbox)

    # 连接服务器函数
    def Talk(self, event):
        s.connect(("127.0.0.1", 8888))
        threadQQ=threading.Thread(target=self.thread_dody,name="Client")
        threadQQ.start()
        return

    def thread_dody(self):
        while True:
            data = s.recv(1024)  # 等待接收服务器端信息
            if len(data) != 0:
                self.text.LabelText += "服务器:" + data.decode() + "rn"  # 将发送信息写入纪录文本框
            time.sleep(1)

    # 发送信息给服务器端
    def on_button(self, event):
        msg = self.inputtext.GetValue()# 获取要发送的文本
        s.send(msg.encode())# 给服务器端发送信息
        self.text.LabelText += "客户端:" + msg + "rn"# 将发送信息写入纪录文本框



class App(wx.App):
    def OnInit(self):
        frame = MyFrame()
        frame.Show()
        return True

if __name__=="__main__":
    app=App()
    app.MainLoop()

学习进步!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值