一、socket简介

1. 套接字

套接字是为特定网络协议(例如TCP/IP,ICMP/IP,UDP/IP等)套件对上的网络应用程序提供者提供当前可移植标准的对象。
它们允许程序接受并进行连接,如发送和接受数据。为了建立通信通道,网络通信的每个端点拥有一个套接字对象极为重要。
套接字为BSD UNIX系统核心的一部分,而且他们也被许多其他类似UNIX的操作系统包括Linux所采纳。
许多非BSD UNIX系统(如ms-dos,windows,os/2,mac os及大部分主机环境)都以库形式提供对套接字的支持。

三种最流行的套接字类型是:stream,datagram和raw。
stream和datagram套接字可以直接与TCP协议进行接口,
raw套接字则接口到IP协议。
但套接字并不限于TCP/IP。

2、套接字模块

套接字模块是一个非常简单的基于对象的接口,它提供对低层BSD套接字样式网络的访问。
使用该模块可以实现客户机和服务器套接字。
要在python 中建立具有TCP和流套接字的简单服务器,需要使用socket模块。
利用该模块包含的函数和类定义,可生成通过网络通信的程序。

3. 一般来说,建立服务器连接需要六个步骤。

第1步: 创建socket对象。
调用socket构造函数。
socket=socket.socket(familly,type)
family的值可以是AF_UNIX(Unix域,用于同一台机器上的进程间通讯),也可以是AF_INET(对于IPV4协议的TCP和 UDP),
至于type参数,SOCK_STREAM(流套接字)或者 SOCK_DGRAM(数据报文套接字),SOCK_RAW(raw套接字)。

第2步: 是将socket绑定(指派)到指定地址上,socket.bind(address)
address必须是一个双元素元组,((host,port)),主机名或者ip地址+端口号。
如果端口号正在被使用或者保留,或者主机名或ip地址错误,则引发socke.error异常。

第3步: 绑定后,必须准备好套接字,以便接受连接请求。
socket.listen(backlog)
backlog指定了最多连接数,至少为1,接到连接请求后,这些请求必须排队,如果队列已满,则拒绝请求。

第4步: 服务器套接字通过socket的accept方法等待客户请求一个连接:
connection,address=socket.accept()
调用accept方法时,socket会进入'waiting'(或阻塞)状态。客户请求连接时,方法建立连接并返回服务器。
accept方法返回一个含有俩个元素的元组,形如(connection,address)。
第一个元素(connection)是新的socket对象,服务器通过它与客户通信;
第二个元素(address)是客户的internet地址。

第5步: 处理阶段,
服务器和客户通过send和recv方法通信(传输数据)。
服务器调用send,并采用字符串形式向客户发送信息。send方法返回已发送的字符个数。
服务器使用recv方法从客户接受信息。调用recv时,必须指定一个整数来控制本次调用所接受的最大数据量。
recv方法在接受数据时会进入'blocket'状态,最后返回一个字符串,用它来表示收到的数据。
如果发送的量超过recv所允许,数据会被截断。
多余的数据将缓冲于接受端。以后调用recv时,多余的数据会从缓冲区删除。

第6步: 传输结束,
服务器调用socket的close方法以关闭连接。

4. 建立一个简单客户连接则需要4个步骤。

第1步,创建一个socket以连接服务器 socket=socket.socket(family,type)
第2步,使用socket的connect方法连接服务器 socket.connect((host,port))
第3步,客户和服务器通过send和recv方法通信。
第4步,结束后,客户通过调用socket的close方法来关闭连接。

5. python 编写server的步骤:

第一步是创建socket对象。调用socket构造函数。如:
socket = socket.socket( family, type )
family参数代表地址家族,可为AF_INET或AF_UNIX。
AF_INET家族包括Internet地址,AF_UNIX家族用于同一台机器上的进程间通信。
type参数代表套接字类型,可为SOCK_STREAM(流套接字)和SOCK_DGRAM(数据报套接字)。
第二步是将socket绑定到指定地址。这是通过socket对象的bind方法来实现的:
socket.bind( address )
由AF_INET所创建的套接字,address地址必须是一个双元素元组,格式是(host,port)。
host代表主机,port代表端口号。
如果端口号正在使用、主机名不正确或端口已被保留,bind方法将引发socket.error异常。
第三步是使用socket套接字的listen方法接收连接请求。
socket.listen( backlog )
backlog指定最多允许多少个客户连接到服务器。它的值至少为1。
收到连接请求后,这些请求需要排队,如果队列满,就拒绝请求。
第四步是服务器套接字通过socket的accept方法等待客户请求一个连接。
connection, address = socket.accept()
调 用accept方法时,socket会时入“waiting”状态。客户请求连接时,方法建立连接并返回服务器。
accept方法返回一个含有两个元素的 元组(connection,address)。
第一个元素connection是新的socket对象,服务器必须通过它与客户通信;
第二个元素 address是客户的Internet地址。
第五步是处理阶段,服务器和客户端通过send和recv方法通信(传输 数据)。
服务器调用send,并采用字符串形式向客户发送信息。send方法返回已发送的字符个数。服务器使用recv方法从客户接收信息。
调用recv 时,服务器必须指定一个整数,它对应于可通过本次方法调用来接收的最大数据量。
recv方法在接收数据时会进入“blocked”状态,最后返回一个字符 串,用它表示收到的数据。
如果发送的数据量超过了recv所允许的,数据会被截短。多余的数据将缓冲于接收端。
以后调用recv时,多余的数据会从缓冲区 删除(以及自上次调用recv以来,客户可能发送的其它任何数据)。

传输结束,服务器调用socket的close方法关闭连接。

6.python编写client的步骤:

创建一个socket以连接服务器:
socket = socket.socket( family, type )

使用socket的connect方法连接服务器。对于AF_INET家族,连接格式如下:
socket.connect( (host,port) )
host代表服务器主机名或IP,port代表服务器进程所绑定的端口号。

如连接成功,客户就可通过套接字与服务器通信,如果连接失败,会引发socket.error异常。
处理阶段,客户和服务器将通过send方法和recv方法通信。
传输结束,客户通过调用socket的close方法关闭连接。

二、socket通信的简单的例子

#!/usr/bin/env python
#
# -*- coding:utf- -*-
# from socket import *
from time import ctime HOST = ''
PORT =
BUFSIZE=
ADDR=(HOST, PORT) tcpSrvSock=socket(AF_INET, SOCK_STREAM)
tcpSrvSock.bind(ADDR)
tcpSrvSock.listen() while True:
print 'waiting for connection ...'
tcpCliSock,addr = tcpSrvSock.accept()
print '... connected from:', addr while True:
data=tcpCliSock.recv(BUFSIZE)
if not data:
break
tcpCliSock.send('[%s] %s'%(ctime(), data))
print [ctime()],':',data tcpCliSock.close()
tcpSrvSock.close()
#!/usr/bin/env python
#
# -*- coding:utf- -*-
# from socket import * HOST='localhost'
PORT=
BUFSIZE=
ADDR=(HOST, PORT) tcpCliSock=socket(AF_INET, SOCK_STREAM)
tcpCliSock.connect(ADDR) while True:
data = raw_input('>')
if not data:
break
tcpCliSock.send(data)
data=tcpCliSock.recv(BUFSIZE)
if not data:
break
print data tcpCliSock.close()

2. TCP client端代码

三、使用SocketServer模块实现TCP和UDP通信

SocketServer模块简化了网络服务器的开发。
它提供了四个基本的服务器类: 
TCPServer : 用于TCP协议,它提供客户端与服务端之间连续的数据流通信;
UDPServer : 用于UDP协议,它的数据封装包是无序的,且有可能会在传输中丢失;
UnixStreamServer和UnixDatagramServer: 它们不经常用;

这四个类处理同步请求,即只有当当前请求处理完成后,才能开始处理下一个请求。
如果每个请求的处理需要很长时间才能完成,这种方式就不是很适合。
因为它要求大量的计算,或因为它返回了大量的数据导致客户端处理很慢。
解决办法是创建一个独立的进程或线程来处理每个请求,
使用 ForkingMixIn和ThreadingMixIn mix-in类能实现异步方式;

创建一个服务器有以下几个步骤,
首先,创建一个BaseRequestHandler类的子类,并重写handle()方法,这个方法将处理输入的请求。
然后,必须实例一个服务器类,并定义它的服务器地址和请求处理类;
最后,调用这个服务器对象的request()或 serve_forever() 方法来处理一个或多个请求。

当继承了ThreadingMixIn来线程化处理连接行为时,需要明确定义你的线程在遇到异常关闭的处理行为。
ThreadingMixIn类定义了一个属性 daemon_threads, 它用来指示服务器是否要等线程线束。
如果你希望线程行为自动处理,你需要显示设置这个标志。
它的默认值是 False,意思是在由ThreadingMinIn创建的线程未退出前,主线程不会退出。

1. TCP通信

#!/usr/bin/env python
# -*- coding:utf- -*-
# import SocketServer class MyTCPHandler(SocketServer.BaseRequestHandler):
"""
The RequestHandler class for our server.
It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
""" def handle(self):
# self.request is the TCP socket connected to the client
self.data = self.request.recv().strip()
print "{} wrote:".format(self.client_address[])
print self.data
# just send back the same data, but upper-cased
self.request.sendall(self.data.upper()) if __name__ == "__main__":
HOST, PORT = "localhost",
# Create the server, binding to localhost on port
SocketServer.TCPServer.allow_reuse_address = True
server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
print " .... waiting for connection" # Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
server.serve_forever()

Server端

#!/usr/bin/env python
# -*- coding:utf- -*-
# from socket import * HOST = 'localhost'
PORT =
BUFSIZE=
ADDR = (HOST, PORT) while True:
tcpCliSock=socket(AF_INET, SOCK_STREAM)
tcpCliSock.connect(ADDR)
data=raw_input('>')
if not data:
break
tcpCliSock.send('%s\r\n' % data)
data=tcpCliSock.recv(BUFSIZE)
if not data:
break
print data.strip()
tcpCliSock.close() 运行示例:
Server
$ python TCPServer.py
127.0.0.1 wrote:
hello world with TCP
127.0.0.1 wrote:
python is nice CLIENT:
$ python TCPClient.py hello world with TCP
Sent: hello world with TCP
Received: HELLO WORLD WITH TCP
$ python TCPClient.py python is nice
Sent: python is nice
Received: PYTHON IS NICE

Client端

四、 使用SocketServer处理多连接

上面的例子一次只能连接一个客户机并出力它的请求,
如果要处理多连接问题,那么有三种主要的方法能实现这个目的:
分叉(forking)、
线程(threading)以及
异步I/O(asynchronous I/O)。

通过对SocketServer服务器使用混入类(mix-in class),派生进程和线程很容易处理。
即使要自己实现它们,这些方法也很容易使用。
它们确实有缺点:
分叉占据资源,并且如果有太多的客户端时分叉不能很好分叉
(尽管如此,对于合理数量的客户端,分叉在现代的UNIX或者Linux系统中是很高效的,如果有一个多CPU系统,那系统效率会更高);
线程处理能导致同步问题。

使用SocketServer框架创建分叉或者线程服务器非常简单:

#!/usr/bin/env python

from SocketServer import (TCPServer as TCP,
StreamRequestHandler as SRH,
ForkingMixIn as FMI)
from time import ctime HOST = ''
PORT =
ADDR = (HOST, PORT) class Server(FMI, TCP):
pass class MyRequestHandler(SRH):
def handle(self):
print '...connected from:', self.client_address
self.wfile.write('[%s] %s' % (ctime(), self.rfile.readline())) tcpServ = Server(ADDR, MyRequestHandler)
print 'waiting for connection...'
tcpServ.serve_forever()

1. 分叉SocketServer服务器:

#!/usr/bin/env python

from SocketServer import (TCPServer as TCP,
StreamRequestHandler as SRH,
ThreadingMixIn as TMI)
from time import ctime HOST = ''
PORT =
ADDR = (HOST, PORT) class Server(TMI, TCP):
pass class MyRequestHandler(SRH):
def handle(self):
print '...connected from:', self.client_address
self.wfile.write('[%s] %s' % (ctime(), self.rfile.readline())) tcpServ = Server(ADDR, MyRequestHandler)
print 'waiting for connection...'
tcpServ.serve_forever()

2. 多线程SocketServer服务器:

import socket
import threading
import SocketServer class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler): def handle(self):
data = self.request.recv()
cur_thread = threading.current_thread()
response = "{}: {}".format(cur_thread.name, data)
self.request.sendall(response) class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
pass def client(ip, port, message):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((ip, port))
try:
sock.sendall(message)
response = sock.recv()
print "Received: {}".format(response)
finally:
sock.close() if __name__ == "__main__":
# Port means to select an arbitrary unused port
HOST, PORT = "localhost", server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
ip, port = server.server_address # Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)
# Exit the server thread when the main thread terminates
server_thread.daemon = True
server_thread.start()
print "Server loop running in thread:", server_thread.name client(ip, port, "Hello World 1")
client(ip, port, "Hello World 2")
client(ip, port, "Hello World 3")
server.shutdown()

3. 异步的SocketServer服务器

socket基础的更多相关文章

  1. C# Socket基础(一)之启动异步服务监听

    本文主要是以代码为主..NET技术交流群 199281001 .欢迎加入. //通知一个或多个正在等待的线程已发生事件. ManualResetEvent manager = new ManualRe ...

  2. php Socket基础

    ◆ Socket 基础PHP使用Berkley的socket库来创建它的连接.socket只不过是一个数据结构.你使用这个socket数据结构去开始一个客户端和服务器之间的会话.这个服务器是一直在监听 ...

  3. 【转】Windows socket基础

    转自:http://blog.csdn.net/ithzhang/article/details/8448655 Windows socket 基础 Windows socket是一套在Windows ...

  4. 从零开始的Python学习Episode 21——socket基础

    socket基础 网络通信要素: A:IP地址   (1) 用来标识网络上一台独立的主机 (2) IP地址 = 网络地址 + 主机地址(网络号:用于识别主机所在的网络/网段.主机号:用于识别该网络中的 ...

  5. Python学习 :socket基础

    socket基础 什么是socket? - socket为接口通道,内部封装了IP地址.端口.协议等信息:我们可以看作是以前的通过电话机拨号上网的年代,socket即为电话线 socket通信流程 我 ...

  6. Python socket 基础(Server) - Foundations of Python Socket

    Python socket 基础 Server - Foundations of Python Socket 通过 python socket 模块建立一个提供 TCP 链接服务的 server 可分 ...

  7. Python socket 基础(Client) - Foundations of Python Socket

    Python socket 基础- Foundations of Python Socket 建立socket - establish socket import socket s = socket. ...

  8. Java IO学习笔记四:Socket基础

    作者:Grey 原文地址:Java IO学习笔记四:Socket基础 准备两个Linux实例(安装好jdk1.8),我准备的两个实例的ip地址分别为: io1实例:192.168.205.138 io ...

  9. Python之路,Day8 - Python基础 面向对象高级进阶与socket基础

    类的成员 类的成员可以分为三大类:字段.方法和属性 注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段.而其他的成员,则都是保存在类中,即:无论对象的 ...

  10. iso socket基础2

    iPhone socket 编程之BSD Socket篇 收藏在进行iPhone网络通讯程序的开发中,不可避免的要利用Socket套接字.iPhone提供了Socket网络编程的接口CFSocket, ...

随机推荐

  1. ES6中的Class

    对于javascript来说,类是一种可选(而不是必须)的设计模式,而且在JavaScript这样的[[Prototype]] 语言中实现类是很蹩脚的. 这种蹩脚的感觉不只是来源于语法,虽然语法是很重 ...

  2. Python TCP客户端

    import socket target_host="www.baidu.com" target_port=80 # 建立一个socket对象 client=socket.sock ...

  3. MySQL大数据分页的优化思路和索引延迟关联

    之前上次在部门的分享会上,听了关于MySQL大数据的分页,即怎样使用limit offset,N来进行大数据的分页,现在做一个记录: 首先我们知道,limit offset,N的时候,MySQL的查询 ...

  4. VS2008的DLL项目添加了方法但是找不到怎么办?

      VS2008中建立了一个DLL项目,使用了一段时间后,在其中一个类中添加了一个方法,然后编译后,拷贝了新的.h文件到使用DLL的项目中,并且.dll和.lib也拷贝到了需要的位置,但是在目标项目中 ...

  5. UVa 414 - Machined Surfaces

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=94&page=s ...

  6. 9.springMVC中的拦截器

    springMVC中的拦截器大概大致可以分为以下几个步骤去学习: 1.自定义一个类实现HandlerInterceptor接口,这里要了解其中几个方法的作用 2.在springMVC的配置文件中添加拦 ...

  7. LR录制https协议报证书错误,导航已阻止

    使用IE浏览器录制https协议报证书错误,导航已阻止,修改如下配置文件:

  8. 项目使用中Linq使用总结

    项目使用中Linq使用总结 本文旨在和网友分享Linq在项目中的实践,曾经我参与过的项目都能看见Linq的影子.(LinqTosql.LinqToString.LinqToXML.LinqToEnti ...

  9. 数据库记录转换成json格式 (2011-03-13 19:48:37) (转)

    http://blog.sina.com.cn/s/blog_621768f30100r6v7.html 数据库记录转换成json格式 (2011-03-13 19:48:37) 转载▼ 标签: 杂谈 ...

  10. python第十二天-----RabbitMQ

    有一位小伙伴说让我去A站写博客可能会有很多人喜欢,真是搞不懂,北方哪里有卖萌?北方默认状态就是这么萌的!再者说了,这明明就是很专注于技术的博客嘛,能不能严肃点!知不知道什么叫帧? 学习到了数据库的相关 ...