Socket编程

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'>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值