一、什么是socket:

  socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求。

   socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)

socket和file的区别:

  1.> file模块是针对某个指定文件进行【打开】【读写】【关闭】

  2.>socket模块是针对 服务器端 和 客户端Socket 进行【打开】【读写】【关闭】

Python 提供了两个基本的 socket 模块。

第一个是 Socket,它提供了标准的 BSD Sockets API。

第二个是 SocketServer, 它提供了服务器中心类,可以简化网络服务器的开发。

socket Server端:

import socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #创建套接字,定义socket类型,网络通信,TCP
s.bind(('localhost',8880)) #绑定套接字到本地IP与端口
s.listen(5) #开始监听TCP连接 while True:
print "waiting....."
conn,addr = s.accept() #接受TCP连接,并返回新的套接字与IP地址
print'Connected by',addr #输出客户端的IP地址
client_data = conn.recv(1024) #接收传来的数据
print client_data
conn.send("hello,we are you server !!!") #发送给对方数据
conn.close() #传输完毕后,关闭套接字

socket Client端

import socket
s = socket.socket() # 创建套接字
s.connect(('localhost',8880)) #连接远端地址,这里为server端的ip和端口
s.send("we are you client") #发送给server端
server_data = s.recv(1024) #接收server端信息
print server_data
s.close() #关闭连接
server端
import socket
ip_port = ('127.0.0.1',8888)
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0)
s.bind(ip_port) while True:
data = s.recv(1024)
print data -------------------------------------------------------------
#client端 import socket
ip_port = ('127.0.0.1',9999) s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0)
while True:
inp = raw_input('data:').strip()
if inp == 'exit':
break
s.sendto(inp,ip_port) s.close()

UDP Demo

使用web访问server端socket.

访问地址:http://localhost:8002

import socket

def main():
# 创建socket对象
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 监听端口
sock.bind(('127.0.0.1',8002))
# 开始监听,
sock.listen(5) while True:
# 阻塞,deng 。。。。
# 直到有请求连接
print '....'
connection, address = sock.accept()
# connection,代表客户端socket对象
# address,客户端IP地址
#handle_request(connection)
buf = connection.recv(1024)
print buf
connection.send("HTTP/1.1 200 OK\r\n\r\n")
connection.send("Hello, World")
connection.close() if __name__ == '__main__':
main()

二、socket常用的几种方法:

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

 参数一:地址簇

   socket.AF_INET IPv4(默认)
  socket.AF_INET6 IPv6   socket.AF_UNIX 只能够用于单一的Unix系统进程间通信 参数二:类型   socket.SOCK_STREAM  流式socket , for TCP (默认)
  socket.SOCK_DGRAM   数据报式socket , for UDP   socket.SOCK_RAW 原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
  socket.SOCK_RDM 是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
  socket.SOCK_SEQPACKET 可靠的连续数据包服务 参数三:协议   0  (默认)与特定的地址家族相关的协议,如果是 0 ,则系统就会根据地址格式和套接类别,自动选择一个合适的协议

s.bind(address)

s.bind(address) 将套接字绑定到地址。address地址的格式取决于地址族。在AF_INET下,以元组(host,port)的形式表示地址。

s.listen(backlog)

开始监听传入连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量.

s.setblocking(bool)

是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。

s.accept()

接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据.address是连接客户端的地址。

s.connect(address)

连接到address处的套接字。一般,address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。

s.connect_ex(address)

和s.connect(address)用法相同,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回编码.

s.recv(bufsize[,flag])

接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。flag提供有关消息的其他信息,通常可以忽略。

s.send(string[,flag])

将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。

s.sendall(string[,flag])

将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。

s.close()

关闭套接字

s.getpeername()

返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。

s.getsockname()

返回套接字自己的地址。通常是一个元组(ipaddr,port)

s.gethostname()

gethostname()返回运行程序所在的计算机的主机名

s.gethostbyname(name)

尝试将给定的主机名解释为一个IP地址

s.fileno()

套接字的文件描述符

单线程聊天机器人实现:(只能同时处理一个连接和请求)

Server端:

#!/usr/bin/env python
# -*- coding:utf-8 -*- import socket ip_port = ('127.0.0.1',8888)
s = socket.socket()
s.bind(ip_port)
s.listen(5) while True:
conn,address = s.accept() #阻塞,等待客户端连接
conn.sendall('welcom 10086,Plz input 1xxx,0转人工服务.')
Flag = True #标志位
while Flag:
#阻塞,等待客户端发送数据.
data = conn.recv(1024)
if data == 'exit':
Flag = False
elif data == '':
conn.sendall('Receive data is zero。。')
else:
conn.sendall('Please re-enter.') #断开与客户端的连接
conn.close()

Client端:

#!/usr/bin/env python
# -*- coding:utf-8 -*- import socket ip_port = ('127.0.0.1',8005)
s = socket.socket()
s.connect(ip_port)
s.settimeout(5) #等待超时时间 while True:
data = s.recv(1024) #接收数据
print 'receive:',data
inp = raw_input('please input:')
sk.sendall(inp)
if inp == 'exit':
break s.close()

SocketServer是标准库中一个高级别的模块。用于简化网络客户与服务器的实现。模块中,已经实现了一些可供使用的类。

编写一个SocketServer需要实现以下步骤:

1.>编写一个handler类,继承BaseRequestHandler,重写handle()方法
2.>针对是TCP还是UDP,生成一个server对象
3.>调用server对象的handle_request或者serve_forever方法

Server端:

 #!/usr/bin/env python
# -*- coding:utf-8 -*- import time
import os
import SocketServer #SocketServer 例子 服务器端
class MyTCPHandler(SocketServer.BaseRequestHandler): #继承SocketServer.BaseRequestHandler 类,底下必须写个handle函数. def handle(self):
print "got commection from",self.client_address #打印客户端地址.
while True: #循环执行.不然执行接收一次数据
self.data = self.request.recv(1024).strip() #接收信息
if not self.data:
time.sleep(1.5)
break
print self.data
cmd = os.popen(self.data)
result = cmd.read()
#format_data = "\033[32;1m%s\033[0m" %self.data #格式化输出
self.request.sendall(result) #返回结果 if __name__ == "__main__":
HOST,PROT = "localhost",8000 server = SocketServer.ThreadingTCPServer((HOST,PROT),MyTCPHandler) #处理多线程连接
server.serve_forever() #永远执行

Clinet端:

 #!/usr/bin/env python
# -*- coding:utf-8 -*- import socket ip_port = ('127.0.0.1',8000)
sk = socket.socket()
sk.connect(ip_port)
sk.settimeout(5) while True: INPUT = raw_input('please input command:')
sk.sendall(INPUT)
data = sk.recv(1024)
print 'receive:',data
if INPUT == "exit":break sk.close()

ThreadingTCPServer实现的Soket服务器内部会为每个client创建一个 “线程”,该线程用来和客户端进行交互。

ThreadingTCPServer源码剖析

ThreadingTCPServer的类图关系如下:

内部调用流程为:

  • 启动服务端程序
  • 执行 TCPServer.__init__ 方法,创建服务端Socket对象并绑定 IP 和 端口
  • 执行 BaseServer.__init__ 方法,将自定义的继承自SocketServer.BaseRequestHandler 的类 MyRequestHandle赋值给 self.RequestHandlerClass
  • 执行 BaseServer.server_forever 方法,While 循环一直监听是否有客户端请求到达 ...
  • 当客户端连接到达服务器
  • 执行 ThreadingMixIn.process_request 方法,创建一个 “线程” 用来处理请求
  • 执行 ThreadingMixIn.process_request_thread 方法
  • 执行 BaseServer.finish_request 方法,执行 self.RequestHandlerClass()  即:执行 自定义 MyRequestHandler 的构造方法(自动调用基类BaseRequestHandler的构造方法,在该构造方法中又会调用 MyRequestHandler的handle方法)

   SocketServer的ThreadingTCPServer之所以可以同时处理请求得益于 selectThreading 两个东西,其实本质上就是在服务器端为每一个客户端创建一个线程,当前线程用来处理对应客户端的请求,所以,可以支持同时n个客户端链接(长连接)。

ForkingTCPServer
ForkingTCPServer和ThreadingTCPServer的使用和执行流程基本一致,只不过在内部ForkingTCPServer为请求者建立 “进程”而ThreadingTCPServer为请求者建立“线程”。

基本使用:

 #!/usr/bin/env python
# -*- coding:utf-8 -*-
import SocketServer class MyServer(SocketServer.BaseRequestHandler): def handle(self):
# print self.request,self.client_address,self.server
conn = self.request
conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.')
Flag = True
while Flag:
data = conn.recv(1024)
if data == 'exit':
Flag = False
elif data == '':
conn.sendall('通过可能会被录音.balabala一大推')
else:
conn.sendall('请重新输入.') if __name__ == '__main__':
server = SocketServer.ForkingTCPServer(('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)
if inp == 'exit':
break sk.close()

客户端

以上代码只是将ThreadingTCPServer替换为 ForkingTCPServer:

 server = SocketServer.ThreadingTCPServer(('127.0.0.1',8009),MyRequestHandler)

 变更为:

 server = SocketServer.ForkingTCPServer(('127.0.0.1',8009),MyRequestHandler)

SocketServer的ForkingTCPServer之所以可以同时处理请求得益于 selectos.fork 两个东西,其实本质上就是在服务器端为每一个客户端创建一个进程,当前新创建的进程用来处理对应客户端的请求,所以,可以支持同时n个客户端链接(长连接)。

 Twisted

Twisted是用Python实现的基于事件驱动的网络引擎框架,其中包含了诸多功能,例如:网络协议、线程、数据库管理、网络操作、电子邮件等。

事件驱动

简而言之,事件驱动分为二个部分:第一,注册事件;第二,触发事件。

自定义事件驱动框架

 #!/usr/bin/env python
# -*- coding:utf-8 -*- # event_drive.py event_list = [] def run():
for event in event_list:
obj = event()
obj.execute() class BaseHandler(object):
"""
用户必须继承该类,从而规范所有类的方法(类似于接口的功能)
"""
def execute(self):
raise Exception('you must overwrite execute')

程序员使用Twisted框架:

#!/usr/bin/env python
# -*- coding:utf-8 -*- from source import event_drive class MyHandler(event_drive.BaseHandler): def execute(self):
print 'event-drive execute MyHandler' event_drive.event_list.append(MyHandler)
event_drive.run()

如上述代码,事件驱动只不过是框架规定了执行顺序,程序员在使用框架时,可以向原执行顺序中注册“事件”,从而在框架执行时可以出发已注册的“事件”。

基于事件驱动Socket

#!/usr/bin/env python

# -*- coding:utf-8 -*-

from twisted.internet import protocol

from twisted.internet import reactor

class Echo(protocol.Protocol):

    def dataReceived(self, data):

        self.transport.write(data)

def main():

    factory = protocol.ServerFactory()

    factory.protocol = Echo

    reactor.listenTCP(8000,factory)

    reactor.run()

if __name__ == '__main__':

    main()

程序执行流程:

  • 运行服务端程序
  • 创建Protocol的派生类Echo
  • 创建ServerFactory对象,并将Echo类封装到其protocol字段中
  • 执行reactor的 listenTCP 方法,内部使用 tcp.Port 创建socket server对象,并将该对象添加到了 reactor的set类型的字段 _read 中
  • 执行reactor的 run 方法,内部执行 while 循环,并通过 select 来监视 _read 中文件描述符是否有变化,循环中...
  • 客户端请求到达
  • 执行reactor的 _doReadOrWrite 方法,其内部通过反射调用 tcp.Port 类的 doRead 方法,内部 accept 客户端连接并创建Server对象实例(用于封装客户端socket信息)和 创建 Echo 对象实例(用于处理请求) ,然后调用 Echo 对象实例的 makeConnection 方法,创建连接。
  • 执行 tcp.Server 类的 doRead 方法,读取数据,
  • 执行 tcp.Server 类的 _dataReceived 方法,如果读取数据内容为空(关闭链接),否则,出发 Echo 的 dataReceived 方法
  • 执行 Echo 的 dataReceived 方法

上述实例本质上使用了事件驱动的方法 和 IO多路复用的机制来进行Socket的处理

 #!/usr/bin/env python
# -*- coding:utf-8 -*- from twisted.internet import reactor, protocol
from twisted.web.client import getPage
from twisted.internet import reactor
import time class Echo(protocol.Protocol): def dataReceived(self, data):
deferred1 = getPage('http://cnblogs.com')
deferred1.addCallback(self.printContents) deferred2 = getPage('http://baidu.com')
deferred2.addCallback(self.printContents) for i in range(2):
time.sleep(1)
print 'execute ',i def execute(self,data):
self.transport.write(data) def printContents(self,content):
print len(content),content[0:100],time.time() def main(): factory = protocol.ServerFactory()
factory.protocol = Echo reactor.listenTCP(8000,factory)
reactor.run() if __name__ == '__main__':
main() 异步IO操作

I/O多路复用操作

参考文档:http://www.cnblogs.com/wupeiqi/articles/5040823.html

Python socket编程的更多相关文章

  1. Python Socket 编程——聊天室示例程序

    上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和客户端的代码了解基本的 Python Socket 编程模型.本文再通过一个例子来加强一下对 Socket 编程的 ...

  2. python/socket编程之粘包

    python/socket编程之粘包 粘包 只有TCP有粘包现象,UDP永远不会粘包. 首先需要掌握一个socket收发消息的原理 发送端可以是1k,1k的发送数据而接受端的应用程序可以2k,2k的提 ...

  3. PYTHON SOCKET编程简介

    原文地址: PYTHON SOCKET编程详细介绍   Python 提供了两个基本的 socket 模块. 第一个是 Socket,它提供了标准的 BSD Sockets API. 第二个是 Soc ...

  4. python socket编程笔记

    用python实现一个简单的socket网络聊天通讯 (Linux --py2.7平台与windows--py3.6平台) 人生苦短之我用Python篇(socket编程) python之路 sock ...

  5. [Python_7] Python Socket 编程

    0. 说明 Python Socket 编程 1. TCP 协议 [TCP Server] 通过 netstat -ano 查看端口是否开启 # -*-coding:utf-8-*- "&q ...

  6. Python Socket 编程示例 Echo Server

    简评:我们已经从「Python Socket 编程概览」了解了 socket API 的概述以及客户端和服务器的通信方式,接下来让我们创建第一个客户端和服务器,我们将从一个简单的实现开始,服务器将简单 ...

  7. Python Socket 编程——聊天室演示样例程序

    上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和client的代码了解主要的 Python Socket 编程模型.本文再通过一个样例来加强一下对 Socket ...

  8. python socket编程入门(编写server实例)+send 与sendall的区别与使用方法

    python 编写server的步骤: 1. 第一步是创建socket对象.调用socket构造函数.如: socket = socket.socket( family, type ) family参 ...

  9. 第九章:Python高级编程-Python socket编程

    第九章:Python高级编程-Python socket编程 Python3高级核心技术97讲 笔记 9.1 弄懂HTTP.Socket.TCP这几个概念 Socket为我们封装好了协议 9.2 cl ...

  10. python socket编程详细介绍

    Python 提供了两个基本的 socket 模块. 第一个是 Socket,它提供了标准的 BSD Sockets API. 第二个是 SocketServer, 它提供了服务器中心类,可以简化网络 ...

随机推荐

  1. 51nod 1060反素数

    经典题. #include<map> #include<queue> #include<stack> #include<cmath> #include& ...

  2. 简单的cookie使用

    <html><head><script type="text/javascript">function getCookie(c_name){if ...

  3. c#读取excel

    Provider根据实际EXCEL的版本来设置,推荐使用ACE接口来读取.需要Access database Engine. 注意修改注册表以下两项的值为0.否则导入EXCEL当单元格内字符长度超过2 ...

  4. 【BZOJ-4353】Play with tree 树链剖分

    4353: Play with tree Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 31  Solved: 19[Submit][Status][ ...

  5. DataTable是否存在某个列的判断

    使用 DataTable.Columns.Contains方法可以判断某个列名是否存在于某个DataTable中 //添加模拟数据 DataTable t = new DataTable(); Dat ...

  6. Apache Mod/Filter Development

    catalog . 引言 . windows下开发apache模块 . mod进阶: 接收客户端数据的 echo 模块 . mod进阶: 可配置的 echo 模块 . mod进阶: 过滤器 0. 引言 ...

  7. 原生JS中常用的Window和DOM对象操作汇总

    一.常用的Window对象操作 Window对象中又包含了document.history.location.Navigator和screen几个对象,每个对象又有自己的属性方法,这里window可以 ...

  8. Xpath用法

    在进行网页抓取的时候,分析定位html节点是获取抓取信息的关键,目前我用的是lxml模块(用来分析XML文档结构的,当然也能分析html结构), 利用其lxml.html的xpath对html进行分析 ...

  9. [Android]关于Activity的InstanceState

    Activity有两个方法onSaveInstanceState() 和 onRestoreInstanceState(). onSaveInstanceState()方法只适合用于保存一些临时性的状 ...

  10. 屠蛟之路_蛟灵岛战役(上)_SixthDay

    乘风破浪,屠蛟少年们终于到达beta怪蛟大boss的老巢--蛟灵岛. 这是一座孤立在东海深处的荒岛,岛上黑烟缭绕.瘴气重重,屠蛟少年们一登岛,就感受到浓浓的腥味和妖气. 果然,再小心翼翼,走两步居然陷 ...