服务端(chat_server.py)
import json
import socket
import traceback
online_users = {}
def decode_msg(msg):
return json.loads(msg.decode('utf-8'))
def encode_msg(msg):
return json.dumps(msg).encode('utf-8')
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(('localhost', 8888))
while True:
try:
recv_message, recv_address = server_socket.recvfrom(1024)
print("收到用户消息: %s, 网络地址 %s" % (recv_message, recv_address))
recv_message = decode_msg(recv_message)
msg_type = recv_message['type']
if msg_type == 'login':
recv_user_name = recv_message['user']
online_users[recv_user_name] = recv_address
for user_name, address in online_users.items():
send_message = {'type': 'online', 'all_users': online_users, 'user': recv_user_name}
server_socket.sendto(encode_msg(send_message), address)
elif msg_type == 'quit':
TCP用于建立可靠连接,并且通信双方可以以流的形式发送数据。相对于TCP,UDP面向无连接的协议。
使用UDP协议时不需要建立连接,只需要知道对方的IP地址和端口号就可以直接发送数据包。但是发送的数据包是否能到达就不 知道了。
虽然用UDP传输数据不可靠,但是优点是速度快。对于不要求可靠到达的数据可以使用UDP协议。
下面来看如何通过UDP协议传输数据。和TCP类似,使用UDP的通信双方也分为客户端和服务器。服务器首先需要绑定端口, 操作如下:
创建socket时,SOCK_DGRAM指定了socket的类型是UDP。绑定端口和TCP一样,不过不需要调用listen()方法,而是直接接 收来自任何客户端的数据,操作如下:
recvfrom()方法返回数据和客户端的地址与端口。这样,服务器收到数据后,直接调用sendto()就可以把数据用UDP发送给客户 端。
客户端使用UDP时,首先仍然是创建基于UDP的socket,然后不需要调用connect(),直接通过sendto()给服务器发送数据,操 作如下:
什么是线程,什么是进程?
进程是程序(软件,应用)的一个执行实例,每个运行中的程序,可以同时创建多个进程,但至少要有一个。每个进程都提供执 行程序所需的所有资源,都有一个虚拟的地址空间、可执行的代码、操作系统的接口、安全的上下文(记录启动该进程的用户和 权限等等)、唯一的进程ID、环境变量、优先级类、最小和最大的工作空间(内存空间)。进程可以包含线程,并且每个进程 必须有至少一个线程。每个进程启动时都会最先产生一个线程,即主线程,然后主线程会再创建其他的子线程。
线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指 令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不独 立拥有系统资源,但它可与同属一个进程的其它线程共享该进程所拥有的全部资源。每一个应用程序都至少有一个进程和一个线 程。在单个程序中同时运行多个线程完成不同的被划分成一块
前面我们了解了TCP/IP协议、IP地址和端口的基本概念,下面我们开始了解网络编程。
网络编程中有一个基本组件——套接字(socket)。套接字主要是两个程序之间的“信息通道”。 程序(通过网络连接)可能 分布在不同的计算机上,通过套接字相互发送信息。
socket是网络编程的一个抽象概念。通常我们用一个socket表示“打开了一个网络连接”,而打开一个socket需要知道目标计 算机的IP地址和端口号,并且指定协议类型。
大多数连接都是可靠的TCP连接。创建TCP连接时,主动发起连接的是客户端,被动响应连接的是服务器。
socket编程交互模型如下图所示
服务器编程首先要绑定一个端口,监听来自其他客户端的连接。如果某个客户端发起连接了,服务器就与该客户端建立socket 连接,随后的通信就靠这个socket连接了。
服务器会打开固定端口监听,每发起一个客户端连接,就创建该socket连接。由于服务器有大量来自客户端的连接,因此要能 够区分一个socket连接是和哪个客户端绑定的。确定4项唯一的socket依赖:服务器地址、服务器端口、客户端地址、客户端端 口。
服务端创建流程
一般来说,建立服务器连接需要6个步骤。
在Python中, import socket 后,用 socket.socket() 方法来创建套接字,语法格式如下
s = socket.socket([family[, type[, proto]]])
参数说明:
直接socket.socket(),则全部使用默认值。
下面是具体的参数定义:
将socket绑定(指派)到指定地址上
socket.bind(address)
address必须是一个双元素元组((host,
计算机网络是独立自主的计算机互联而成的系统的总称,组建计算机网络最主要的目的是实现多台计算机之间的通信和资源共 享。
今天计算机网络中的设备和计算机网络的用户已经多得不可计数,而计算机网络也可以称得上是一个“复杂巨系统”.
1960s - 美国国防部ARPANET (阿帕网络(Advanced Research Project Agency Network))项目问世,奠定了分组交 换网络的基础。
1980s - 国际标准化组织(ISO)发布OSI/RM,奠定了网络技术标准化的基础。
1990s - 英国人蒂姆·伯纳斯-李发明了图形化的浏览器,浏览器的简单易用性使得计算机网络迅速被普及。
在没有浏览器的年代,上网是这样的。
有了浏览器以后,上网是这样的。
实现网络通信的基础是网络通信协议,这些协议通常是由互联网工程任务组 (IETF)制定的。
所谓“协议”就是通信计算机双方必须共同遵从的一组约定,例如怎样建立连接、怎样互相识别等,网络协议的三要素是:语 法、语义和时序。
构成我们今天使用的Internet的基础的是TCP/IP协议族,所谓协议族就是一系列的协议及其构成的通信模型,我们通常也把这套 东西称为TCP/IP模型。
与国际标准化组织发布的OSI/RM这个七层模型不同,TCP/IP是一个四层模型,也就是说,该模型将我们使用的网络从逻辑上分 解为四个层次,自底向上依次是:网络接口层、网络层、传输层和应用层,如下图所示。
IP通常被翻译为网际协议,它服务于网络层,主要实现了寻址和路由的功能。
接入网络的每一台主机都需要有自己的IP地址,IP地址就是主机在计算机网络上的身份标识
当然由于IPv4地址的匮乏,我们平常在家里、办公室以及其他可以接入网络的公共区域上网时获得的IP地址并不是全球唯一的IP 地址,而是一个局域网(LAN)中的内部IP地址,通过网络地址转换(NAT)服务我们也可以实现对网络的访问。
计算机网络上有大量的被我们称为“路由器”的网络中继设备,它们会存储转发我们发送到网络上的数据分组,让从源头发出的 数据最终能够
定时任务, 让控件在 delay_ms 毫秒后去调用函数 func , 其中 args 为函数的参数
格式为:
w.after(delay_ms, func=None, *args)
方法返回值为int类型的标识符, 可以使用 .after_cancel() 方法取消定时任务
向控件添加一个事件绑定
格式为:
w.bind(sequence=None, func=None, add=None)
参数 sequence 指的是事件名, func 是回调函数, 当该事件已经绑定到一个回调函数上, 默认情况会使用新函数覆盖老函数, 使 用 add='+' 保留新旧两个
事件格式: <[modifier-]...type[-detail]>
事件名如何表示:
函数格式:
def 函数名(事件参数)
如:
tkinter 中的控制变量,可以在不同的部件中共用,使用 set (value) 方法设置变量值后,所有相关的部件会在屏幕更新時自动更 新;控制变量的建立必须使用以下三种类别之一:
控制变量的方法
文本框组件常用的方法:
delete(first, last=None)
从组件中删除字符, 从 first 索引位置开始, 到 last (不包含)索引位置结束. 如果 last 参数没有的话, 只删除 first 一个字符, 例如: text.delete(10); text.delte(10,20); text.delete(0,tkinter.END);text.delete(0, 'end')
insert(index, s)
在 index 索引位置前插入字符串s, text.insert(0,"sss")
text.get()
entry的索引有以下几种表示方式:
该模块实现了各种分布的伪随机数生成器。
几乎所有模块函数都依赖于基本函数 random() ,它在半开放区间 [0.0,1.0) 内均匀生成随机浮点数。
import random
常用的方法如下:
random.randrange([start], stop[, step])
,从指定范围内,按指定基数递增的集合中 获取一个随机数。如:random.randrange(10, 100, 2)
,结果相当于从[10, 12, 14, 16, … 96, 98]序列中获取一个随机数。
random.choice
从序列中获取一个随机元素。其函数原型为:random.choice(sequence)
。参数sequence表示一个有序 类型。这里要说明 一下:sequ
单选按钮控件;显示一个单选的按钮状态
单选按钮控件仅允许用户选择单一的选项值,各个选项值之间是互斥的关系,因此只有一个选项可以被用户选择。
Radiobutton 控件通常都是成组出现的,所有控件都使用相同的变量。
语法格式如下:
radio=tkinter.Radiobutton(master, options...)
例如:
var_radio = tkinter.IntVar()
radio = tkinter.Radiobutton(window, text="弱", disabledforeground='red', value=1, variable=var_radio)
radio.grid(row=1, column=2)
radio = tkinter.Radiobutton(window, text="中", disabledforeground='red', value=2, variable=var_radio)
radio.grid(row=1, column=3)
radio = tkinter.Radiobutton(window, text="强", disabledforeground='red', value=3, variable=var_radio)
radio.grid(row=1, column=4)
Radiobutton 属性列表,如下所示:
\n
换行注意:
radiobutton成组出现时: variable参数一定要是同一个, 并且value参数不能相同
Combobox 控件,也就是下拉菜单控件(或称复合框),该控件是列表控件的改进版,具有更加灵活的界面,因此其应
Tkinter 是使用 python 进行窗口视窗设计的模块。Tkinter模块(“Tk 接口”)是Python的标准Tk GUI工具包的接口。
Graphical User Interface 图形用户接口
tkinter是python 自带的, 可以编辑的GUI界面,我们可以用GUI 实现很多直观的功能,比如想开发一个计算器,如果只是一个 程序输入,输出窗口的话,是没用用户体验的。所有开发一个图像化的小窗口,就是必要的。
在GUI编程中,顶层的根窗口对象包含组成GUI应用的所有小窗口对象,它们可以是文字标签、按钮、列表框等,这些独立的 GUI组件称为控件。当创建一个顶层窗口时,指的是需要一个地方来摆放所有的控件。
在Python中,一般用如下语句创建根窗口:
import tkinter
top=tkinter.Tk()
或者
from tkinter import *
top=Tk()
tkinter.Tk() 返回的对象通常称为根窗口
顶层窗口是那些在应用中独立显示的部分,GUI程序中可以有多个顶层窗口,但只能有一个根窗口。
件可以独立存在,也可以作为容器存在。如果一个控件包含其他控件,就可以称其为其他控件的父控件。若一个控件被其他控件 包含,则称其为那个控件的子控件,而父控件就称为包围它的容器控件。
控件有一些相关的行为,如按下按钮、将文本写入文本框等,这些行为称为事件,而GUI对这类事件的响应称为回调。
事件包括按下按钮及释放、鼠标移动、按回车键等。一个GUI应用从开始到结束就是通过整套事件体系来驱动的,这种方式称为 事件驱动处理。
tkinter有3种布局管理器,即Placer、Packer和Grid。
Placer是最原始的布局管理器,Placer的做法非常直接,只需提供控件的 大小和摆放位 置,然后管理器就会自动将其摆放好。但 这有一个问题,就是你必须对所有控件进行这些操作,这会加重编程开发者的负担,因为这些操作本应该是自动完成的
btn.place(x=100,y=100)
Packer
x,y=12,5
if x % y==0:
z=x/y
print(x,"/",y,"=",z)
else:
z=y*x
print(x,"*",y,"=",z)
程序段执行后,输出的结果为?( )
A、x/y=2.4
B、x*y=60
C、12/5=2.4
D、12*5=60
A、t=(1,2,'信息')
B、t=(1)
C、t=('信息',)
D、t='音乐','体育','美术'
A、a.remove()
B、a.pop()
C、a.clear()
D、del a
A、a[-7:-2:-2]
B、a[2:7:2]
C、a[3:7:2]
D、a[2:7:-2]
alist=['cat','bat','cat','hat','cat']
,执行下列代码,输出的结果是?( )
alist.remove('cat')
print(alist)
A、['cat','bat','cat','hat','cat']
B、['bat','cat','hat','cat']
C、['bat','hat']
D、['cat','bat','cat','hat']
A、3
B、4
C、5
D、6
tup=(1,2,3,4,5)
执行的操作非法的是?( )
A、len(tup)
B、max(tup)
C、min(tup)
D、tup[1] = 6
A、map(int,L)
B、list(map(i