一、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. Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.

    今天碰到了一个查询异常问题,上网查了一下,感谢原创和译者 如果你使用的数据库连接类是 the Data Access Application Blocks "SqlHelper" ...

  2. Linux 相关基础笔记

    html,body { } .CodeMirror { height: auto } .CodeMirror-scroll { } .CodeMirror-lines { padding: 4px 0 ...

  3. 一步步编写avalon组件02:分页组件

    本章节,我们做分页组件,这是一个非常常用的组件.grid, listview都离不开它.因此其各种形态也有. 本章节教授的是一个比较纯正的形态,bootstrap风格的那种分页栏. 我们建立一个ms- ...

  4. Oracle中 Package与Package body的介绍

    1.Oracle Package的作用: 可以简化应用设计.提高应用性能.实现信息隐藏.子程序重载 2.ORACLE中的function   .package.package   bodies.pro ...

  5. 深入理解js——隐式原型

    每个函数都有一个prototye(原型),而每个对象都有一个_proto_,可成为隐式原型. _proto_是一个隐藏的属性,javascript不希望开发者用到这个属性值,有的低版本浏览器甚至不支持 ...

  6. a + b + c 求和

    #include <iostream> int main() { std::cout << "请输入三个数字,以空格分隔,按回车键结束:" << ...

  7. 安卓 io流 写入文件,再读取的基本使用

    1.布局 布局里面只有一个EditView,通过输入内容之后,当触发 onDestroy 方法时,将输入的数据存储在当前应用的data/data/files文件夹下. <?xml version ...

  8. 简单的jquery插件写法之一

    http://jsfiddle.net/kyu0hdmx/embedded/#HTML

  9. [转] 你是as3老鸟吗?但是有些你可能目前都不知道的东西

    你是as3老鸟吗?如果以下内容对你有莫大的帮助,请顶下! 一:加载swf库中的图片 new 的过程就是图片解压缩的过程.处于 Class 状态时,图片占用的内存和 SWF 文件中这个图片占用的磁盘空间 ...

  10. 技术英文单词贴--E

    E element 元素,成分,要素 expire 到期,终止,期满