html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video { margin: 0; padding: 0; border: 0 }
body { font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14px; line-height: 1.6; color: #333; background-color: #fff; padding: 20px; max-width: 960px; margin: 0 auto }
body>*:first-child { margin-top: 0 !important }
body>*:last-child { margin-bottom: 0 !important }
p,blockquote,ul,ol,dl,table,pre { margin: 15px 0 }
h1,h2,h3,h4,h5,h6 { margin: 20px 0 10px; padding: 0; font-weight: bold }
h1 tt,h1 code,h2 tt,h2 code,h3 tt,h3 code,h4 tt,h4 code,h5 tt,h5 code,h6 tt,h6 code { font-size: inherit }
h1 { font-size: 28px; color: #000 }
h2 { font-size: 24px; border-bottom: 1px solid #ccc; color: #000 }
h3 { font-size: 18px }
h4 { font-size: 16px }
h5 { font-size: 14px }
h6 { color: #777; font-size: 14px }
body>h2:first-child,body>h1:first-child,body>h1:first-child+h2,body>h3:first-child,body>h4:first-child,body>h5:first-child,body>h6:first-child { margin-top: 0; padding-top: 0 }
a:first-child h1,a:first-child h2,a:first-child h3,a:first-child h4,a:first-child h5,a:first-child h6 { margin-top: 0; padding-top: 0 }
h1+p,h2+p,h3+p,h4+p,h5+p,h6+p { margin-top: 10px }
a { color: #4183C4; text-decoration: none }
a:hover { text-decoration: underline }
ul,ol { padding-left: 30px }
ul li>:first-child,ol li>:first-child,ul li ul:first-of-type,ol li ol:first-of-type,ul li ol:first-of-type,ol li ul:first-of-type { margin-top: 0px }
ul ul,ul ol,ol ol,ol ul { margin-bottom: 0 }
dl { padding: 0 }
dl dt { font-size: 14px; font-weight: bold; font-style: italic; padding: 0; margin: 15px 0 5px }
dl dt:first-child { padding: 0 }
dl dt>:first-child { margin-top: 0px }
dl dt>:last-child { margin-bottom: 0px }
dl dd { margin: 0 0 15px; padding: 0 15px }
dl dd>:first-child { margin-top: 0px }
dl dd>:last-child { margin-bottom: 0px }
pre,code,tt { font-size: 12px; font-family: Consolas, "Liberation Mono", Courier, monospace }
code,tt { margin: 0 0px; padding: 0px 0px; white-space: nowrap; border: 1px solid #eaeaea; background-color: #f8f8f8 }
pre>code { margin: 0; padding: 0; white-space: pre; border: none; background: transparent }
pre { background-color: #f8f8f8; border: 1px solid #ccc; font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px }
pre code,pre tt { background-color: transparent; border: none }
kbd { background-color: #DDDDDD; background-image: linear-gradient(#F1F1F1, #DDDDDD); background-repeat: repeat-x; border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD; border-style: solid; border-width: 1px; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; line-height: 10px; padding: 1px 4px }
blockquote { border-left: 4px solid #DDD; padding: 0 15px; color: #777 }
blockquote>:first-child { margin-top: 0px }
blockquote>:last-child { margin-bottom: 0px }
hr { clear: both; margin: 15px 0; height: 0px; overflow: hidden; border: none; background: transparent; border-bottom: 4px solid #ddd; padding: 0 }
table th { font-weight: bold }
table th,table td { border: 1px solid #ccc; padding: 6px 13px }
table tr { border-top: 1px solid #ccc; background-color: #fff }
table tr:nth-child(2n) { background-color: #f8f8f8 }
img { max-width: 100% }
socket编程之TCP编程
socket是网络编程的一个抽象概念.通常我们用Socket表示"打开了一个网络连接",而打开一个Socket需要知道目标计算机的ip 地址和端口号,再指定协议即可.
在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
客户端/服务端架构
即C/S架构,包括
1.硬件C/S架构(打印机)
2.软件C/S架构(web服务)
客户端(c端)
- 大多数连接是可靠的TCP连接 ,创建TCP连接时,主动发起连接的叫客户端,被动响应连接的叫服务器.
举个栗子,我们把socket的过程比喻为一个打电话的过程,创建一个基于TCP链接的Socket:
import socket#导入socket模块
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#创建一个socket(拿一个电话)
phone.connect(("127.0.0.1",8080))#建立连接(拨电话)
其中,AF_INET表示指定ipv4协议,如果要更加先进的ipv6 ,可以指定 AF_INET6.目前ipv4还是主流. SOCK_STREAM指定指定面向流的TCP协议,这样一个Socket对象就创建成功.
其中("127.0.0.1",8080),前者是是服务器的ip,也可以用域名代替,后者是服务器端口号,作为服务器,ip和端口都应该是固定的.
注意("127.0.0.1",8080)是一个元祖.
建立TCP连接后,我们就可以向服务器发送请求,要求返回.
phone.send(msg.encode("utf-8"))#发送数据(对服务端说话)
TCP连接创建的是双向通道,双方都可以互相发数据.
data= phone.recv(1024)#接收服务端数据(听服务端的话)
print(data.decode("utf-8"))#显示出来
接收数据时,用recv(max)方法.其中括号指定一次最多接收的字节数.
当我们接收完数据后,调用close()方法关闭Socket,这样,一次完整的网络通信就结束了:
phone.close()#关闭连接(挂电话)
服务器(s端)
和客户端编程相比,服务器编程就要复杂一些。
服务器进程首先要绑定一个端口并监听来自客户端的连接.所以服务器会打开固定端口监听,每一个客户端连接就创建该Socket连接.由于服务器会有大量来自客户端的连接,所以,服务器要能够区分一个Socket连接是和哪个客户端绑定的。一个Socket依赖4项:服务器地址、服务器端口、客户端地址、客户端端口来唯一确定一个Socket。
首先,创建一个基于IPv4和TCP协议的Socket:
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#同上,建立socket
然后,我们要绑定监听的地址和端口.端口号需要预先指定
phone.bind(("127.0.0.1",8080))#监听端口
phone.listen(5)#开始监听(5代表传入的参数指定等待连接的最大数量)
接下来,服务端程序用一个死循环来接收客户端的连接,accept()会等待并返回一个客户端的连接
while True:
conn,addr=phone.accept()#建立连接
然后,服务端程序用一个死循环开始接受客户端的数据,并返回数据
while True:
conn,addr=phone.accept()#建立连接
while True:
try:#建立异常处理机制,当客户端断开连接时,直接退出本层接收数据的循环,返回建立连接的循环
data=conn.recv(1024)#接收客户端数据
if not data:break#消息为空则重复循环
print("客户端发来的消息",data.decode("utf-8"))#打印客户端发来的数据
conn.send("好几把炫酷!".encode("utf-8"))#返回数据给客户端
except Exception:
break
conn.close()#关闭本次连接
我们从头到尾来一遍:
#服务端
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(("127.0.0.1",8080))
phone.listen(5)
print("starting")
while True:
conn,addr=phone.accept()
while True:
try:
data=conn.recv(1024)
if not data:break
print("客户端发来的消息",data.decode("utf-8"))
conn.send("好几把炫酷!".encode("utf-8"))
except Exception:
break
conn.close()
phone.close()
#客户端
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(("127.0.0.1",8080))
while True:
msg=input(">>>")
if not msg:continue
if msg=="quit":break
phone.send(msg.encode("utf-8"))
data= phone.recv(1024)
print(data.decode("utf-8"))
phone.close()
小结
用TCP协议进行Socket编程在python中十分简单,对于客户端,要主动连接服务端的ip和指定端口,对于服务端,则是监听指定端口.