Socket通长也称作"套接字",用于描述IP地址和端口,是一个通信的句柄.

vim day8-16.py

#!/usr/bin/env python
#coding:utf-8
import socket

def handle_request(client):
    buf = client.recv(1024)
    print buf
    client.send("HTTP/1.1 200 OK\r\n\r\n")
    client.send("Hello, World")

def main():
    #创建socket对象
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    #bind方法监听某个端口
    sock.bind(('127.0.0.1',8080))
    #开始监听,
    sock.listen(5)

    while True:
        #阻塞,等...
        #直到有请求连接
        connection, address = sock.accept()
        #connection代表客户端sockert对象
        #address客户端IP地址
        handle_request(connection)
        connection.close()

if __name__ == '__main__':
  main()

运行,然后在开启一个客户端访问

Python之socket_客户端

本客户端返回

Python之socket_数据_02

 

使用python建立一个socket的服务端和客户端

vim socket_server.py        

#!/usr/bin/env python
#coding:utf-8


import socket

obj_server = socket.socket()
obj_server.bind(('localhost',8341))
obj_server.listen(5)                    #开始监听最大连接数5
while True:
    print 'waiting...'
    conn,addr = obj_server.accept()
    client_data =  conn.recv(1024)                      #最多一次性接收1024size
    print client_data
    conn.send('好的')
    conn.close()
                  

vim  socket_client.py

#!/usr/bin/env python
#coding:utf-8

import socket


obj = socket.socket()
obj.connect(('localhost',8341))
obj.send('我爱北京天安门')
server_data = obj.recv(1024)
print server_data
obj.close()
~                

运行服务端,然后新开一个窗口运行客户端

Python之socket_数据_03

Python之socket_数据_04

 

智能机器人实例

vim day8-18.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import socket

ip_port = ('127.0.0.1',8888)
sk = socket.socket()
sk.bind(ip_port)
sk.listen(5)

while True:
    conn,address = sk.accept()
    conn.sendall('欢迎致电10086,请输入1xxx,0转人工服务')
    Flag = True
    while Flag:
        data = conn.recv(1024)                  #阻塞等待客户端发生数据
        print data                              #打印从客户端接收到的数据
        if data == 'exit':
            Flag = False
        elif data == '0':
            conn.sendall('您的通话可能被录音')
        else:
            conn.sendall('请重新输入')
    conn.close()

vim day8-19.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import socket

ip_port = ('127.0.0.1',8888)
sk = socket.socket()
sk.connect(ip_port)                     #客户端连接服务端
sk.settimeout(5)

while True:
    data = sk.recv(1024)                #接收服务端数据欢迎致电...
    print 'recevie:',data
    inp = raw_input('please input:')
    sk.sendall(inp)
    if inp == 'exit':
        break

sk.close()

执行过程

服务端

Python之socket_vim_05

客户端

Python之socket_服务端_06

PS:一个socket同时只能处理一个请求,如果一个请求在连接中,其他请求在过来将排队等待,等待时间为设置的超时时间为5s,python提供了一个模块用于多线程模块socketserver

 

SoketServer

多线程条件

1,必须写一个类

2,必须继承SocketServer.BaseRequestHandler

3,必须写一个方法而且方法名必须为handle

4,必须调用ThreadingTCPServer方法来实现多线程

day8-22.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import SocketServer
import os
class MyServer(SocketServer.BaseRequestHandler):

    def handle(self):
        print "--got connection from", self.client_address
        while True:
            data = self.request.recv(1024)
            print "Recv from cmd:%s" %(data)
            cmd_res = os.popen(data).read()
            print 'cmd_res:',len(cmd_res)       #打印服务器发送数据长度
            self.request.sendall(cmd_res)

if __name__ == '__main__':
    server = SocketServer.ThreadingTCPServer(('127.0.0.1',8009),MyServer)
    server.serve_forever()                              #永久运行

客户端vim day8-23.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import socket


ip_port = ('127.0.0.1',8009)
sk = socket.socket()
sk.connect(ip_port)
sk.settimeout(5)

while True:
#    data = sk.recv(1024)
#    print 'receive:',data
    inp = raw_input('please input:')
    sk.sendall(inp)
    while True:
        data = sk.recv(1024)
        print "---data---"
#       if len(data) == 0:
        if len(data) < 1024:
            print '---not data---'
            break
        print data
    if inp == 'exit':
        break

sk.close()

客户端输入命令服务端把命令结果返回给客户端打印

 

修改代码让服务器在发送数据之前就把要发送的大小发送给客户端,客户端根据包的大小进行判断打印

服务端

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import SocketServer
import os
class MyServer(SocketServer.BaseRequestHandler):

    def handle(self):
        print "--got connection from", self.client_address
        while True:
            data = self.request.recv(1024)
            print "Recv from cmd:%s" %(data)	
            cmd_res = os.popen(data).read()
	    print 'cmd_res:',len(cmd_res)	#打印服务器发送数据长度
            self.request.send( str(len(cmd_res)) ) #服务端要给客户端发多长数据
	    self.request.sendall(cmd_res)

if __name__ == '__main__':
    server = SocketServer.ThreadingTCPServer(('127.0.0.1',8009),MyServer)
    server.serve_forever()				#永久运行

客户端

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import socket


ip_port = ('127.0.0.1',8009)
sk = socket.socket()
sk.connect(ip_port)
sk.settimeout(5)

while True:
#    data = sk.recv(1024)
#    print 'receive:',data
    inp = raw_input('please input:')
    sk.sendall(inp)
    res_size = sk.recv(1024)
    print "goint to recv data size:",res_size,type(res_size)#打印将收到多少数据和数据类型
    
    total_size = int(res_size)					#共要收取的
    received_size = 0
    while True:
	data = sk.recv(1024)
	received_size += len(data)
	print "---data---"
#	if len(data) == 0:
#	if len(data) < 1024:
	if total_size == received_size:			#如果收到的大小等于收到的大小代表收完了
	    print data
	    print '---not data---'
	    break
        print data
    if inp == 'exit':
        break

sk.close()

PS:这样也会出现问题,这两个包可能在网络层集合成一个包发送给客户端导致客户端接收ValueError,这种现象叫连包,可以通过修改服务器端代码(比如两个包之间sleep1秒再发送下一个包),但是效率太低

Python之socket_服务端_07

可以通过在两条消息直接加代码解决

服务端

Python之socket_客户端_08

 客户端回一条可以是一个空格

Python之socket_python_09

 

作业:客户端往服务端发文件,客户端可以从服务端下载文件,实现文件MD5验证和用户验证