网络编程的基本概念:
网络的七层:
第七层:应用层
第六层:表示层
第五层:会话层
第四层:传输层
第三层:网络层
第二层:数据链路层
第一层:物理层
IP地址分为A,B,C,D,E五类。
网络号:用于识别主机所在的网络;
主机号:用于识别该网络中的主机。
1. A类地址
⑴ A类地址第1字节为网络地址,其它3个字节为主机地址。
⑵ A类地址范围:1.0.0.1—126.155.255.254
⑶ A类地址中的私有地址和保留地址:
① 10.X.X.X是私有地址(所谓的私有地址就是在互联网上不使用,而被用在局域网络中的地址)。
② 127.X.X.X是保留地址,用做循环测试用的。
2. B类地址
⑴ B类地址第1字节和第2字节为网络地址,其它2个字节为主机地址。
⑵ B类地址范围:128.0.0.1—191.255.255.254。
⑶ B类地址的私有地址和保留地址
① 172.16.0.0—172.31.255.255是私有地址
② 169.254.X.X是保留地址。如果你的IP地址是自动获取IP地址,而你在网络上又没有找到可用的DHCP服务器。就会得到其中一个IP。
⑴ C类地址第1字节、第2字节和第3个字节为网络地址,第4个个字节为主机地址。另外第1个字节的前三位固定为110。
⑵ C类地址范围: 192.0.0.1—223.255.255.254 。
⑶ C类地址中的私有地址:
192.168.X.X 是私有地址。
4. D类地址
⑴ D类地址不分网络地址和主机地址,它的第1个字节的前四位固定为1110。
⑵ D类地址范围: 224.0.0.1—239.255.255.254
5. E类地址
⑴ E类地址也不分网络地址和主机地址,它的第1个字节的前五位固定为11110。
⑵ E类地址范围: 240.0.0.1—255.255.255.254
TCP: TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议,它完成第四层传输层所指定的功能..
UDP: UDP是一种简单的面向数据报、无连接、传输层协议,并且保留了信息边界。UDP不提供错误校正,不保证有序,无法去重复,没有流量控制和拥塞控制,不能保证数据一定到达目的地,但是可以通过校验和提供错误侦测。UDP提供的的是不可靠传输,因此要有应用层来提供这些功能。
端口: 端口号的范围从0到65535,0~1024端口系统已分配,后面可以使用。一个端口就是一个连接应用。
Socket(套接字):
Socket类型:
Socket.AF_UNIX : 只能够用于单一的Unix系统进程间通信
Socker.AF_INET : 服务器之间网络通信
Socket.AF_INET6 : IPv6(现在很少使用IPv6)
Socket.SOCK_STREAM : 流式socket,for TCP
Socket.SOCK_DGRAM : 数据报式socket, forUDP
Socket.SOCK_RAW : 原始套接字,普通的套接字无法处理ICMP,IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头.
Socket.SOCK_SEQPACKET : 可靠的连续数据包服务
Socket函数:
1.服务端socket函数:
s.bind(address): 将套接字绑定到地址,在AF_INET下,以元组(host,port)的形式表示地址.
注:host表示ip地址,port表示对端口
s.listen(backlog): 开始监听TCP传入连接,backlog指定在拒接连接之前,操作系统可以挂起最大连接数量.该值至少为1,大部分应用程序设为5就可以了.
s.accept() : 表示服务器等待连接,接受TCP连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据.address是连接客户端的地址.
2.客户端socket函数:
s.connect(address) : (用于服务器连接,)连接到address处的套接字.一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误
s.connect_ex(address) : 功能与connect(address)相同,但是成功返回0,失败返回error的值
3.公共socket函数:
s.recv(bufsize[,flag]): 接受TCP套接字的数据.数据以字符串形式返回,bufsize指定要接收的最大数据量.flag提供有关消息的其他信息,通常可以忽然.
s.send(string[,flag]) : 发送TCP数据.将string中的数据发送到连接的套接字.返回值是要发送的字节数量,该数量肯小于string的字节大小.
s.sendall(string[,flag]): 完整发送TCP数据.将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据.成功返回None,失败则抛出异常.
s.recvfrom(bufsize[,flag]): 接受UDP套接字的数据.与recv类似,但返回值是(data,address).其中data是包含接收数据的字符串,address是发送数据的套接字地址.
s.sendto(string[,flag],address): 发送UDP数据.将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址,返回值是发送的字节数.
s.close(): 关闭套接字
s.getpeername(): 返回连接套接字的远程地址,返回值通常是元组(ipaddr,port)
s.setsockname(): 返回套接字自己的地址.通常是一个元组(ipadd,port)
s.setsockopt(level,optname,value) : 设置给定套接字选项的值.
s.getsockopt(level,optname,[,buflen]): 返回套接字选项的值
s.settimrout(timeout): 设置套接字操作的超时期,timcout是一个浮点数,单位是秒.值为None表示没有超时期.一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作
s.gettimeout(): 返回当前超时期的值,单位是秒,如果没有设置超时期,则返回None
s.fileno(): 返回套接字的文件描述符.
s.setblocking(flag): 如果flag为0,则将套接字设为非阻塞模式(默认值),非阻塞模式下,如果调用recv()没有发现任何数据,或者scnd()调用无法立即发送数据,那么将引起socket.error异常.
s.makefile() : 创建一个与该套接字相关连的文件
要使用scoket.scoket()函数来创建套接字.其语法如下:
导入模块:import socket
创建TCP socket: s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
创建 UDP socket: s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
下面例子实现一个简单的服务器与客户端的通话:
服务器:
import socket,threading secv=socket.socket(socket.AF_INET,socket.SOCK_STREAM) secv.bind(("127.0.0.1",9999)) print("服务器已启动") secv.listen(5) c=secv.accept() print(c) def myrerv(c): while True: msg = c[0].recv(1024)#接收消息 print(msg.decode()) threading._start_new_thread(myrerv,(c,)) def myinput(): while True: msg=input() c[0].send(msg.encode())#服务器发送消息 threading._start_new_thread(myinput())客户端:
import socket,threading client=socket.socket(socket.AF_INET,socket.SOCK_STREAM) client.connect(("127.0.0.1",9999))#ip127.0.0.1代表本机的ip,9999是端口号,是自己设置的但是服务器和客户端的端口号要一致 print("客户端已连接") def myrerv(c): while True: msg = c.recv(1024)#接收消息 print(msg.decode()) threading._start_new_thread(myrerv,(client,)) def myinput(): while True: msg=input("某某说的话:) client.send(msg.encode()) threading._start_new_thread(myinput())
这只是一个服务器与客户端的通话,当我们需要实现多个客户端与服务器通话时实现群聊时,我们需要对服务器代码进行优化一下,代码如下:
import socket,threading sercv=socket.socket(socket.AF_INET,socket.SOCK_STREAM) sercv.bind(("127.0.0.1",9999)) print("服务器已连接!") sercv.listen(5) msg=None lock=threading.Lock() mythread=threading.Condition(lock=lock) def server_recv(c,a): global msg while True: mystr=c.recv(1024) mythread.acquire() msg=str(a) + mystr.decode() print(msg) mythread.notify_all() mythread.release() def server_send(c): global msg while True: mythread.acquire() mythread.wait() mythread.release() c.send(msg.encode()) print(msg) while True: c,a=sercv.accept() threading._start_new_thread(server_recv,(c,a)) threading._start_new_thread(server_send,(c,))注:在通话时必须先启动服务器代码否则会报异常.