1 概述
1.1 Socket 是什么
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口
1.1.1 Socket 在哪里
1.1.2 socket如何交互
服务端:
初始化socket,与端口进行绑定,对端口进行监听,调用accept阻塞,等待客户端连接。
此时,如果有一个客户端初始化socket,然后连接服务器,如果连接成功,这时客户端与服务器端的连接就建立了。
客户端发送数据请求,服务端接收并处理请求,然后把应答数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
1.2 网络中的进程如何通信:socket
通过三元组标识网络中的进程(ip地址,协议,端口),网络中的进程就可以利用这个标志与其它进程进行通信。
一切皆socket
Linux的哲学之一就是:一切皆文件——都可以用打开open,读read/写write,关闭close模式来进行操作。
我的理解就是Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭),这些函数我们在后面进行介绍。
2 使用
Socket的基本操作
既然socket是“open—write/read—close”模式的一种实现,那么socket就提供了这些操作对应的函数接口。下面以TCP为例,介绍几个基本的socket接口函数。
socket 是一种特殊的I/O
服务端函数:
bind,listen,accept
客户端函数:
connect,connet_ex
2.1 socket() 函数
socket(family,type[,protocal])
socket 函数 相当于一个open 操作。
普通文件的打开操作返回一个文件描述字,而socket()用于创建一个socket描述符(socket descriptor),它唯一标识一个socket。
这个描述字与文件描述字一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作。
socket函数的三个参数分别为:
family:即协议域,又称为协议族(family)。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。
套接字分类:1、基于文件类型的套接字家族;套接字家族的名字:AF_UNIX
2、基于网络类型的套接字家族;套接字家族的名字:AF_INET
type:指定socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等.
流式Socket(SOCK_STREAM)流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;
**数据报式Socket(SOCK_DGRAM)**数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。
protocol:故名思意,就是指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议
当我们调用socket创建一个socket时,返回的socket描述字它存在于协议族(address family,AF_XXX)空间中,但没有一个具体的地址。如果想要给它赋值一个地址,就必须调用bind()函数
不使用bind(),当调用connect()、listen()时系统就会自动随机分配一个端口。
2.2 bind () 函数
s.bind(address)
将套接字绑定到地址, 在AF_INET下,以元组(host,port)的形式表示地址address
通常服务器在启动的时候都会绑定一个众所周知的地址(如ip地址+端口号),用于提供服务,客户就可以通过它来接连服务器;而客户端就不用指定,有系统自动分配一个端口号和自身的ip地址组合。这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个。
2.3 listen()
s.listen(backlog)
开始监听TCP传入连接。
backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5就可以了。
2.4 accept()
s.accept()
接受TCP连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。
同时,也起到了阻塞进程的作用。
2.5 connect
s.connect(address)
连接到address处的套接字。一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。
2.6 接收数据
s.recv(bufsize[,flag])
接收TCP套接字的数据。
数据以字符串形式返回。
bufsize指定要接收的最大数据量。
flag提供有关消息的其他信息,通常可以忽略。
s.recvfrom(bufsize[.flag])
接受UDP套接字的数据。
与recv()类似,但返回值是(data,address)。
其中data是包含接收数据的字符串,address是发送数据的套接字地址。
2.7 发送
send(string[,flag])
发送TCP数据。将string中的数据发送到连接的套接字。
返回值是要发送的字节数量,该数量可能小于string的字节大小.
sendall(string[,flag])
完整发送TCP数据。
将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。
s.sendto(string[,flag],address)
发送UDP数据。将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。
返回套接字
s.getpeername()
返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。
s.getsockname()
返回套接字自己的地址。通常是一个元组(ipaddr,port)
超时
s.settimeout(timeout)
设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如connect())
s.gettimeout()
返回当前超时期的值,单位是秒,如果没有设置超时期,则返回None。
s.setblocking(flag)
如果flag为0,则将套接字设为非阻塞模式,否则将套接字设为阻塞模式(默认值)。非阻塞模式下,如果调用recv()没有发现任何数据,或send()调用无法立即发送数据,那么将引起socket.error异常。
3 socket编程
3.1 编程思路
TCP服务端:
1 创建套接字,绑定套接字到本地IP与端口
socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind()
2 开始监听连接
#s.listen()
3 进入循环,不断接受客户端的连接请求
#s.accept()
4 然后接收传来的数据,并发送给对方数据
#s.recv() , s.sendall()
5 传输完毕后,关闭套接字
#s.close()
TCP客户端:
1 创建套接字,连接远端地址
# socket.socket(socket.AF_INET,socket.SOCK_STREAM) ,
# s.connect()
2 连接后发送数据和接收数据
# s.sendall()
# s.recv()
3 传输完毕后,关闭套接字
#s.close()
3.2 代码实例
Socket编程之服务端代码:
import socket #socket模块
import commands #执行系统命令模块
HOST='10.0.0.245'
PORT=50007
s= socket.socket(socket.AF_INET,socket.SOCK_STREAM) #定义socket类型,网络通信,TCP
s.bind((HOST,PORT)) #套接字绑定的IP与端口
s.listen(1) #开始TCP监听,监听1个请求
while 1:
conn,addr=s.accept() #接受TCP连接,并返回新的套接字与IP地址
print'Connected by',addr #输出客户端的IP地址
while 1:
data=conn.recv(1024) #把接收的数据实例化
cmd_status,cmd_result=commands.getstatusoutput(data)
#commands.getstatusoutput执行系统命令(即shell命令),返回两个结果,第一个是状态,成功则为0,第二个是执行成功或失败的输出信息
if len(cmd_result.strip()) ==0: #如果输出结果长度为0,则告诉客户端完成。此用法针对于创建文件或目录,创建成功不会有输出信息
conn.sendall('Done.')
else:
conn.sendall(cmd_result) #否则就把结果发给对端(即客户端)
conn.close() #关闭连接
Socket编程之客户端代码:
import socket
HOST='10.0.0.245'
PORT=50007
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #定义socket类型,网络通信,TCP
s.connect((HOST,PORT)) #要连接的IP与端口
while 1:
cmd=raw_input("Please input cmd:") #与人交互,输入命令
s.sendall(cmd) #把命令发送给对端
data=s.recv(1024) #把接收的数据定义为变量
print data #输出变量
s.close() #关闭连接
https://www.cnblogs.com/wumingxiaoyao/p/7047658.html
if __ name __ ==‘main’ 用法
if __name__== '__main__':
python脚本的执行方式有两种:
1、作为脚本直接执行
2、Import到其它的脚本中被调用(模块重用)执行
if name==‘main’: 只有在第一种方式下才运行
init() 与 self对象
class Person(object):
def __init__(self, name, lang, website):
self.name = name
self.lang = lang
self.website = website
print('self: ', self)
print('type of self: ', type(self))
'''
未实例化时,运行程序,构造方法没有运行
'''
p = Person('Tim', 'English', 'www.universal.com')
'''实例化后运行的结果
self: <__main__.Person object at 0x00000000021EAF98>
type of self: <class '__main__.Person'>