Client/Server Architecture (CS架构)

说socket之前先说一点cs架构的问题。什么是CS架构? 不同的人对于这个问题有不同的回答以及你说的是硬件还是软件,但是无论哪一种情况都离不开一个前提假设:服务端是为一台或多台客服端提提供服务的硬件和软件的结合体。它存在的仅有的目的就是等待客服端的请求,对客服端提供反应,之后等待更多的请求。

  客服端(client)为特殊的请求链接服务器,发送必要的数据,等待服务器回复,要么完成请求要么失败。服务端无限制的运行,不断的处理请求;客服端向服务端发送一次请求,接受服务,然后结束处理。一个客服端可能一次后会向服务端做出另外的请求,但是这些看做是分开的处理。

Definition - What does Client/Server Architecture mean?

Client/server architecture is a computing model in which the server hosts, delivers and manages most of the resources and services to be consumed by the client. This type of architecture has one or more client computers connected to a central server over a network or Internet connection. This system shares computing resources.

Client/server architecture may also be referred to as a networking computing model because all the requests and services are delivered over a network.

Techopedia explains Client/Server Architecture

Client/server architecture is a producer-consumer computing architecture where the server acts as the producer and the client as a consumer. The server houses and provides high-end, computing-intensive services to the client on demand. These services can include applications access, storage, file sharing, printer access and/or direct access to the server’s raw computing power. 

Client/server architecture works when the client computer sends a resource or process request to the server over the network connection, which is then processed and delivered to the client. A server computer can manage several clients simultaneously, whereas one client can be connected to several servers at a time, each providing a different set of services. In its simplest form, the Internet is also based on client/server architecture where the Web server serves many simultaneous users with Web page and or website data.

                                     

 

Socket (套接字)

什么是socket?socket是计算机网络数据结构。在任何类型的通讯开始之前,网络应用必须创建socket。他们就像电话插孔,没有插孔想要通讯是不可能的。

  BSD Unix (Berkeley version of Unix) 有时也称为Berkeley sockets or BSD sockets. 创造Sockets 源于他们能够使得一个运行程序去和其他应用程序在相同的服务器应用内交流。这个也被称为interprocess communication,or IPC. 有两种类型的Sockets:file-based (基于文件型) 和 network-oriented (面向网络型).

  Unix sockets 有一个AF_UNIX族名(在类UNIX上叫AF_LOCAL)。许多平台使用address families或者缩写为AF,一些老的系统可能称address families为域 (domains) 或者原型族 (protocol families)并且使用PF而不是使用AF。AF_LOCAL被认为是要取代AF_UNIX,由于向后的兼容性;许多系统使用二者并将其命名为相同的常量。Python仍然使用AF_UNIX。这些sockets是基于文件,意味着文件系统支持这些底层基础结构。

IPv6 (Internet Protocol version 6)使用。

  总体上,Python仅仅支持AF_UNIX, AF_NETLINK, AF_TIPC,和AF_INET{,6}族。我们主要集中AF_INET。

Socket地址 (主机—端口对)

  Socket就像电话插孔,能够使得通讯的基础结构;之后主机名和端口就像地区编码和与之相连的电话数字。一个网络地址包含需要通信的主机名和端口数字对。有效的端口数字范围是0-65535,小于1024的端口数字保留给系统。

面向连接sockets和无连接sockets

  不管你使用哪一种地址族,总是有两种不同类型的socket连接。第一种类型是面向连接 (connection-oriented),也就意味着在通讯之前必须建立连接。这种类型的socket称为虚拟环(virtual circuit)或者 流socket (stream socket)。

  面向连接通讯提供顺序的、可靠的、和无法复制的传输数据,没有记录边界。这意味着每一条信息可以分解成许多片,保证他们到达他们的目的,按顺序组合然后传输给等待的应用。

  主要运用连接类型的原型是TCP (Transmission Control Protocol)。创造TCP sockes 必须使用SOCK_STREAM作为socket类型。

  无连接的socket在通讯之前不需要建立连接。并不保证提供顺序的、可靠的、和无法复制的传输数据,数据包(datagrams)保留记录边界。这意味着整个信息被传输而不是分成小片。

   主要运用连接类型的原型是UDP (User Datagram Protocol)。创造UDP sockes 必须使用SOCK_DGRAM作为socket类型。

socket() 模块功能

创造一个socket,你必须使用socket.socket()功能,语法如下:



socket(socket_family,socket_type,protocol = 0)



socket_family要么是AF_UNIX要么是AF_INET,socket_type要么是SOCK_STREAM要么是SOCK_DGRAM,protocol通常被省略掉,默认是0。

创造一个TCP/IP socket,语法如下:



tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)



创造一个UDP/IP socket,语法如下:



udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)



由于socket模块有众多的属性,这是唯一可以使用from socket import * 的例外。

socket对象内建方法

服务端socket方法:

s.bind()        绑定(主机名端口数字)地址到socket上
s.listen()        创建开始TCP收听者数
s.accept()       被动接受TCP客服端连接,一直等待到连接到达

客服端socket方法:

s.connect()       激活开始的TCP服务端连接
s.connect_ex()      connect()的扩展版本,返回问题的错误代码,而不是抛出异常

一般的socket方法:

s.recv()          接受TCP信息
s.recv_into()       接受TCP信息放进具体的缓冲
s.send()          传输TCP信息
s.sendall()         完全传输TCP信息
s.recvfrom()        接受UDP信息 
s.recvfrom_into()     接受UDP信息放进具体的缓冲
s.sendto()        传输UDP信息
s.getpeername()      返回远程连接到的socket地址
s.getsockname()      返回当前socket地址
s.getsockopt()        返回给定socket的值
s.setsockopt()        设置给定socket的值
s.shutdown()        关闭连接
s.close()           关闭socket 
s.detach()           关闭socket没有关闭文件描述,返回后者
s.ioctl()           仅仅在windons下控制模块

面向阻塞socket方法:

s.setblocking()       建立阻塞或非阻塞socket模式
s.settimeout()        对阻塞操作建立超时
s.gettimeout()        获得阻塞操作的超时

面向文件socket方法:

s.fileno()           socket的文件描述
s.makefile()         创建与socket关联的文件对象

数据属性:

s.family            socket族
s.type             socket类型
s.proto            socket原型

创造TCP服务端



ss = socket()                        # create server socket
ss.bind()                            # bind socket to address
ss.listen()                          # listen for connections
inf_loop:                            # server infinite loop
  cs = ss.accept()                   # accept client connection
  comm_loop:                         # communication loop
    cs.recv()/cs.send()              # dialog (receive/send)
  cs.close()                         # close client socket
ss.close()                           # close server socket # (opt)



TCP Timestamp Server (tsTserv.py)



1 #!/usr/bin/env python
 2 #coding:utf-8
 3 
 4 from socket import *
 5 from time import ctime
 6 
 7 HOST = ''
 8 PORT = 1024
 9 BUFSIZE =1023
10 ADD = (HOST,PORT)
11 tcpsocket = socket(AF_INET,SOCK_STREAM)
12 
13 tcpsocket.bind(ADD)
14 tcpsocket.listen(5)
15 
16 while True:
17         print 'waiting for connection...'
18         connection,addr = tcpsocket.accept()
19         print '... connected from',addr
20         
21         while True:
22             data = connection.recv(BUFSIZE)
23             if not data:
24                 break
25             connection.send('[%s] %s'%(ctime(),data))
26         connection.close()
27 tcpsocket.close()



HOST变量是空,HOST显示给bind()方法它能使用的可用的地址。我们能使用一个随机端口数字,不能出现被使用或者被保存在系统数字。创建了1K大小的缓冲大小,你能根据你的网络能力和应用需要改变大小。listen()方法参数仅仅是接受连接请求最大数量。

创造TCP客服端



cs = socket()                 # create client socket
cs.connect()                  # attempt server connection
comm_loop:                    # communication loop
  cs.send()/cs.recv()         # dialog (send/receive)
cs.close()                    # close client socket



TCP Timestamp Client (tsTclnt.py)



1 #!/usr/bin/env python
 2 #coding:utf-8
 3 
 4 from socket import *
 5 
 6 HOST = 'localhost'
 7 PORT = 1024
 8 BUFSIZE = 1023
 9 ADD = (HOST,PORT)
10 
11 client = socket(AF_INET,SOCK_STREAM)
12 client.connect(ADD)
13 
14 while True:
15     data = raw_input(">")
16     if not data:
17         break
18     client.send(data)
19     data = client.recv(BUFSIZE)
20     if not data:
21         break
22     print data
23 client.close()



客服端PORT应该服务端PORT相同。

创建UDP服务器



1 ss = socket()               # create server socket
2 ss.bind()                 # bind server socket
3 inf_loop:                 # server infinite loop
4   cs = ss.recvfrom()/ss.sendto()  # dialog (receive/send)
5 ss.close()                # close server socket



UDP Timestamp Server (tsUserv.py)



1 #!/usr/bin/env python
 2 #coding:utf-8
 3 
 4 from socket import *
 5 from time import ctime
 6 
 7 HOST = ''
 8 PORT = 4321
 9 ADDR = (HOST,PORT)
10 BUFSIZE = 1024
11 udpsocket = socket(AF_INET,SOCK_DGRAM)
12 udpsocket.bind(ADDR)
13 
14 while True:
15     print 'waiting for message...'
16     data,addr = udpsocket.recvfrom(BUFSIZE)
17     
18     udpsocket.sendto('[%s] %s' %(ctime(),data),addr)
19     print '...received from and returned to:', addr
20 udpsocket.close()



创造UDP客服端

 



1 cs = socket()                       # create client socket
2 comm_loop:                          # communication loop
3 cs.sendto()/cs.recvfrom()           # dialog (send/receive)
4 cs.close()                          # close client socket



 

UDP Timestamp Client (tsUclnt.py)



1 #!/usr/bin/env python
 2 #coding:utf-8
 3 
 4 from socket import *
 5 
 6 HOST = 'localhost'
 7 PORT = 4321
 8 ADDR = (HOST,PORT)
 9 BUFSIZE = 1024
10 udpclient = socket(AF_INET,SOCK_DGRAM)
11 
12 while True:
13     data = raw_input('>')
14     if not data:
15         break
16     udpclient.sendto(data,ADDR)
17     data,addr = udpclient.recvfrom(BUFSIZE)
18     if not data:
19         break
20     print data
21 udpclient.close()



 未完待续... (过一段时间之后将正则表达式、socket、socketserver一同更新完)