C/S模式

由于网络课需要实现Socket网络编程,所以简单实现了一下,C/S模式分别用TCP/IP协议与UDP协议实现,下面将分别讲解。

TCP/IP协议

TCP/IP协议是面向连接的,即客户端与服务器需要先建立连接后才能传输数据,以下是服务器端的代码实现。

服务端:

import socket

from threading import Thread

def deal(sock,addr):

print('Accept new connection from {}:{}'.format(addr[0],addr[1]))

sock.send('与服务器连接成功!'.encode('utf-8'))

while True:

data = sock.recv(1024).decode('utf-8') #1024为接收数据的最大大小

print('receive from {}:{} :{}'.format(addr[0],addr[1],data))

sock.send('信息已成功收到'.encode('utf-8'))

##创建tcp/IPV4协议的socket

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

#为socket绑定端口

s.bind(('127.0.0.1',10240))

#监听端口,参数5为等待的最大连接量

s.listen(5)

print("Waiting for connection...")

while True:

sock,addr = s.accept()

t1 = Thread(target=deal,args=(sock,addr))

t1.start()

#断开与该客户端的连接

sock.close()

s.close()

需要注意的是,服务器在等待客户端连接时,即accept()函数这里是阻塞的,如下代码每次只能接受一个客户端的连接。

while True:

#接受一个新连接,accept等待并返回一个客户端连接

sock,addr = s.accept()

print('Accept new connection from {}:{}'.format(addr[0],addr[1]))

#给客户端发送消息

sock.send('连接成功!'.encode('utf-8'))

while True:

data = sock.recv(1024).decode('utf-8') #1024为接收数据的最大大小

print('receive from {}:{} :{}'.format(addr[0],addr[1],data))

sock.send('信息已成功收到'.encode('utf-8'))

#断开与该客户端的连接

sock.close()

也就是说如果采用以上方式,一个客户端与服务器建立连接后,服务器就会进入一个死循环去收发该客户端的信息,因此需要引入多线程,每与一个客户端建立连接,就为其创建一个线程用于控制信息的收发,这样便可以接受多个客户端的连接了。

客户端:

import socket

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

##建立连接

s.connect(('127.0.0.1',10240))

#接收客户端连接成功服务器发来的消息

print(s.recv(1024).decode('utf-8'))

while True:

data = input('发送给服务器:')

if len(data)>0:

s.send(data.encode('utf-8'))

print('form sever:{}'.format(s.recv(1024).decode('utf-8')))

s.close()

客户端是比较简单的,需要与服务器建立连接后,再进行收发信息,这里不再赘述了。

UDP协议

UDP协议是面向无连接的,即服务器与客户端不需要提前建立连接,只需要向指定的端口直接发送数据即可。

服务端

import socket

#为服务器创建socket并绑定端口 SOCK_DGRAM指定了socket的类型为udp

s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

s.bind(('127.0.0.1',7890))

print('Waiting for data...')

#upd无需监听

while True:

data,addr = s.recvfrom(1024)

print('Recevie from {}:{} :{}'.format(addr[0],addr[1],data.decode('utf-8')))

#sendto的另一个参数为客户端socket地址

s.sendto('信息已成功收到!'.encode('utf-8'),addr)

客户端

import socket

#为服务器创建socket并绑定端口 SOCK_DGRAM指定了socket的类型为udp

s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

while True:

data = input('发送给服务器:')

s.sendto(data.encode('utf-8'),('127.0.0.1',7890))

print('Receive from sever:{}'.format(s.recv(1024).decode('utf-8')))

可以看到UDP协议是非常简单的,由于不需要建立连接,所以也不需要创建线程来管理数据的收发。

C/S模式的应用程序

使用PyQt5对以上的程序进行封装,这是基于TCP/IP协议实现的。

服务端

from PyQt5.QtWidgets import (QApplication,QPushButton,

QWidget,QLineEdit,QTextEdit)

import sys

import socket

from threading import Thread

import datetime

class UI(QWidget):

def __init__(self):

super().__init__()

self.initUI()

def initUI(self):

#控件

self.clear_btn = QPushButton('清空内容',self)

self.text = QTextEdit(self)

#布局

self.clear_btn.setGeometry(150,400,100,40)

self.text.setGeometry(20,20,360,370)

self.text.setReadOnly(True)

#信号连接

self.clear_btn.clicked.connect(self.commit)

#初始化socket

self.s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

##建立连接

self.s.bind(('127.0.0.1',10240))

self.s.listen(5)

self.text.setText("Waiting for connection...")

self.t = Thread(target = self.recv,args = ())

self.t.start()

#主窗口布局

self.setGeometry(300, 300, 400, 450)

self.setWindowTitle('Server')

self.show()

def commit(self):

self.text.clear()

def recv(self):

while True:

sock,addr = self.s.accept()

t1 = Thread(target=self.deal,args=(sock,addr))

t1.start()

sock.close()

def deal(self,sock,addr):

#sock,addr = s.accept()

self.text.append('Accept new connection from {}:{}'.format(addr[0],addr[1]))

sock.send('与服务器连接成功!'.encode('utf-8'))

while True:

data = sock.recv(1024).decode('utf-8') #1024为接收数据的最大大小

self.text.append('[{}] receive from {}:{} :{}'.format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),addr[0],addr[1],data))

sock.send('信息已成功收到'.encode('utf-8'))

sock.close()

def closeEvent(self,event):

self.s.close()

event.accept()

if __name__ == '__main__':

app = QApplication(sys.argv)

ex = UI()

sys.exit(app.exec_())

这里需要注意的是,由于Qt的主程序本身一直处于循环,如果直接阻塞等待客户端连接会导致程序崩溃,因此需要在Qt初始化时创建一个线程用于等待客户端的连接,要想同时多个客户端访问服务器,还需要在连接成功后再创建一个线程单独用于接收该客户端的数据。

客户端

from PyQt5.QtWidgets import (QApplication,QPushButton,

QWidget,QLineEdit,QTextEdit)

import sys

import socket

from threading import Thread

import datetime

class UI(QWidget):

def __init__(self):

super().__init__()

self.initUI()

def initUI(self):

#控件

self.edit = QLineEdit(self)

self.commit_btn = QPushButton('发送',self)

self.text = QTextEdit(self)

#布局

self.edit.setGeometry(20, 410, 280, 30)

self.commit_btn.setGeometry(310,410,70,30)

self.text.setGeometry(20,20,360,380)

self.text.setReadOnly(True)

#信号连接

self.commit_btn.clicked.connect(self.commit)

#初始化socket

self.s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

##建立连接

self.s.connect(('127.0.0.1',10240))

self.text.setText('服务器 [{}]:{}\n'.format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),self.s.recv(1024).decode('utf-8')))

#主窗口布局

self.setGeometry(300, 300, 400, 450)

self.setWindowTitle('Client')

self.show()

def commit(self):

if len(self.edit.text()):

text = self.edit.text()

self.s.send(text.encode('utf-8'))

self.text.append('本机 [{}]:{}\n'.format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),text))

self.text.append('服务器 [{}]:{}\n'.format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),self.s.recv(1024).decode('utf-8')))

self.edit.clear()

def closeEvent(self,event):

self.s.close()

event.accept()

def recv(self):

while True:

pass

if __name__ == '__main__':

app = QApplication(sys.argv)

ex = UI()

sys.exit(app.exec_())

客户端还是比较简单,不需要创建线程,在发送按纽点击时触发事件,向服务器发送数据,并将发送的数据与服务器返回的数据显示在textEdit上。

P2P模式

老师说P2P模式就是用两个服务器相互连接通信(我以为是要客户端发送给服务器,服务器再转发给另一个客户端),为了实现方便,直接采用UDP协议,也不用创建那么多线程了。代码如下:

from PyQt5.QtWidgets import (QApplication,QPushButton,

QWidget,QLineEdit,QTextEdit,QLabel)

import sys

import socket

from threading import Thread

import datetime

class UI(QWidget):

def __init__(self):

super().__init__()

self.initUI()

def initUI(self):

#控件

self.edit = QLineEdit(self)

self.commit_btn = QPushButton('发送',self)

self.text = QTextEdit(self)

self.host_label = QLabel('ip地址:',self)

self.host = QLineEdit(self)

self.dst_port_label = QLabel('目标端口:',self)

self.dst_port_edit = QLineEdit(self)

self.src_port_label = QLabel('本机端口:',self)

self.src_port_edit = QLineEdit(self)

self.que_ren_btn = QPushButton('确认',self)

#self.host_label.setStyleSheet("QLabel{font-size:25px}")

#self.dst_port_label.setStyleSheet("QLabel{font-size:25px}")

#self.src_port_label.setStyleSheet("QLabel{font-size:25px}")

#布局

self.edit.setGeometry(20, 480, 280, 30)

self.commit_btn.setGeometry(310,480,70,30)

self.text.setGeometry(20,90,360,380)

self.host_label.setGeometry(20,20,65,25)

self.host.setGeometry(90,20,110,25)

self.dst_port_label.setGeometry(205,20,65,25)

self.dst_port_edit.setGeometry(275,20,110,25)

self.src_port_label.setGeometry(20,55,65,25)

self.src_port_edit.setGeometry(90,55,110,25)

self.que_ren_btn.setGeometry(205,55,70,25)

self.text.setReadOnly(True)

#信号连接

self.commit_btn.clicked.connect(self.commit)

self.que_ren_btn.clicked.connect(self.que_ren)

#初始化socket

self.s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

#主窗口布局

self.setGeometry(300, 300, 400, 520)

self.setWindowTitle('Client')

self.show()

def commit(self):

if len(self.edit.text()):

text = self.edit.text()

self.s.sendto(text.encode('utf-8'),('127.0.0.1',self.dst_port))

self.text.append('本机 [{}]:\n{}\n'.format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),text))

self.edit.clear()

def closeEvent(self,event):

self.s.close()

event.accept()

def recv(self):

while True:

data,addr = self.s.recvfrom(1024)

self.text.append('{}:{}[{}]:\n{}\n'.format(addr[0],addr[1],datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),data.decode('utf-8')))

def que_ren(self):

self.src_port = int(self.src_port_edit.text())

self.dst_port = int(self.dst_port_edit.text())

#绑定ip地址与端口

self.s.bind(('127.0.0.1',self.src_port))

#开启接收消息的线程

self.t = Thread(target=self.recv,args=())

self.t.start()

if __name__ == '__main__':

app = QApplication(sys.argv)

ex = UI()

sys.exit(app.exec_())

首先需要输入要传送信息的IP地址,以及端口号,以及设置自己的端口号(IP地址没有用到,我设置了是127.0.0.1),点击确定按钮时触发事件,会为socket绑定端口号,并且创建一个用于接收消息的线程,在点击发送按钮时会触发另一个事件用于发送消息,发送与接收的消息最后会显示在TextEdit上。

注意

这里要统一说明一下,在使用Qt封装后程序会一直循环运行,导致关闭程序时socket也没有关闭(因为我也刚学,不清楚不关闭的后果,可能会占用这个端口一段时间吧),因此需要重写Qt的closeEvent函数,在该函数中进行关闭。

总结

到此这篇关于python Socket网络编程实现C/S模式和P2P的文章就介绍到这了,更多相关python Socket C/S模式和P2P内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

pythonp2p网络_python Socket网络编程实现C/S模式和P2P相关推荐

  1. Windows/Linux TCP Socket网络编程简介及测试代码

    典型的网络应用是由一对程序(即客户程序和服务器程序)组成的,它们位于两个不同的端系统中.当运行这两个程序时,创建了一个客户进程和一个服务器进程,同时它们通过从套接字(socket)读出和写入数据在彼此 ...

  2. Linux C++/Java/Web/OC Socket网络编程

    一,Linux C++ Socket网络编程 1.什么是TCP/IP.UDP? TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制 ...

  3. python运维开发之socket网络编程01

    python运维开发之socket网络编程01说明:本文来自来自北京老男孩linux运维实战培训中心-运维开发课程免费视频内容,本文内容为系列内容,更多分享信息见:http://oldboy.blog ...

  4. Socket网络编程(2)--服务端实现

    中秋了,首先祝大家中秋快乐,闲着无事在家整一个socket的聊天程序,有点仿QQ界面,就是瞎折腾,不知道最后是不是能将所有功能实现. 如果你对socket不了解,请看这篇文章:http://www.c ...

  5. Linux Kernel TCP/IP Stack — Socket Layer — TCP/UDP Socket 网络编程

    目录 文章目录 目录 TCP/UDP Socket 逻辑架构 创建 Socket 绑定 Socket 请求建立 Socket 连接 监听 Socket 接受请求 关闭连接 数据的发送和接收 send ...

  6. Socket网络编程笔记

    网络.计算机网络的构成是什么? 网络: 在计算机领域中,网络是信息传输.接收.共享的虚拟平台,通过它可以把各个点.面(组织之间).体(例如公共app)的信息联系到一起,从而实现这些资源的共享. 局域网 ...

  7. 【Socket网络编程】14. perror()、errno 的使用

    经常会在socket网络编程时看到errno和perror(),他们是什么呢? 函数定义: void perror(const char *s); perror ("open_port&qu ...

  8. socket网络编程——套接字地址结构

    声明:此博客是本人根据老师课件总结的,如有抄袭行为,本人会即刻删除. 1.主机字节序列和网络字节序列 主机字节序列分为大端字节序和小端字节序,不同的主机采用的字节序列可能不同.大端字节序是指一个整数的 ...

  9. 【网络编程】之四、socket网络编程例解

    前面说了那么多,现在我们给出4个代码+详解,基于win32平台的socket编程.使用TCP 和 UDP 两种协议. OK,先来看一下TCP服务器和客户端: [cpp] view plaincopy ...

  10. MFC socket网络编程(流程示例)

    MFC socket网络编程(流程示例) 1.TCP流式套接字的编程步骤 在使用之前须链接库函数:工程->设置->Link->输入ws2_32.lib,OK! 服务器端程序: 1.加 ...

最新文章

  1. 请写出查询该表中成绩最大值的sql语句_SQL-汇总分析
  2. canvas-js贝塞尔曲线代码在线生成工具
  3. php pdo 打印sql语句,php – 使用PDO准备SQL语句
  4. 翻译关于ViewController的一篇文章
  5. Python处理PDF与CDF
  6. python中pos的用法_Python:数组、队列及堆栈的使用(list用法)--转
  7. CentOS 6.3 64bit 搭建vsFTP服务
  8. Java中集合(四)LinkedList
  9. 21.Longest Palindromic Substring(最长回文子串)
  10. 解释性语言和汇编性语言对比
  11. 架构师未来性的基础:简单性
  12. DB2 错误代码 命令大全
  13. matlab save txt 乱码,matlab代码或中文复制到word就变成乱码怎么办?
  14. stack示例_C.示例中的Stack.CopyTo()方法
  15. Linux中查看socket进程状态
  16. 简单实现x的n次方pta_Day12 :数值的整数次方
  17. linux 中文ssid 显示乱码,两招解决网络设置 支持中文SSID
  18. 思维导图制作工具BLUMIND 小巧免激活 免安装 仅2M
  19. NPN与PNP型传感器的区别
  20. Python 测试广告语敏感词

热门文章

  1. 我的站(艾网---城市生活新门户)重新上线了
  2. Spring IOC 概述
  3. css相关笔记(一)
  4. ubuntu 16.04 和win10双系统ubuntu无法更新问题解决
  5. echart 折线统计图
  6. 董洁经纪人挑拨离间,潘粤明称董洁经纪人插手婚姻
  7. 转-流框架中DOMContentLoaded事件的实现
  8. sql server的数据同步
  9. Transformers Assemble(PART I)
  10. 【业界分享】字节跳动如何用 7 年,成为腾讯最可怕的对手?张一鸣一语道破...