zoukankan      html  css  js  c++  java
  • 网络编程之socket的运用

    一,socket用法

    socket是什么 ?

    Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

    所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。

    套接字的发展史及分类

    套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD Unix。 因此,有时人们也把套接字称为“伯克利套接字”或“BSD 套接字”。一开始,套接字被设计用在同 一台主机上多个应用程序之间的通讯。这也被称进程间通讯,或 IPC。套接字有两种(或者称为有两个种族),分别是基于文件型的和基于网络型的。 

    基于文件类型的套接字家族

    套接字家族的名字:AF_UNIX

    unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信

    基于网络类型的套接字家族

    套接字家族的名字:AF_INET

    (还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET)

     套接字工作流程

     一个生活中的场景。你要打电话给一个朋友,先拨号,朋友听到电话铃声后提起电话,这时你和你的朋友就建立起了连接,就可以讲话了。等交流结束,挂断电话结束此次交谈。 生活中的场景就解释了这工作原理。

          

                                               图3       

    先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束

    服务端套接字函数
    s.bind() 绑定(主机,端口号)到套接字
    s.listen() 开始TCP监听
    s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来

    客户端套接字函数
    s.connect() 主动初始化TCP服务器连接
    s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常

    公共用途的套接字函数
    s.recv() 接收TCP数据
    s.send() 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
    s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
    s.recvfrom() 接收UDP数据
    s.sendto() 发送UDP数据
    s.getpeername() 连接到当前套接字的远端的地址
    s.getsockname() 当前套接字的地址
    s.getsockopt() 返回指定套接字的参数
    s.setsockopt() 设置指定套接字的参数
    s.close() 关闭套接字

    面向锁的套接字方法
    s.setblocking() 设置套接字的阻塞与非阻塞模式
    s.settimeout() 设置阻塞套接字操作的超时时间
    s.gettimeout() 得到阻塞套接字操作的超时时间

    面向文件的套接字的函数
    s.fileno() 套接字的文件描述符
    s.makefile() 创建一个与该套接字相关的文件

     

    1,先用socket实现一个简单的ssh

    ssh服务端

    1 import socket,os
     2 server=socket.socket()
     3 server.bind(('127.0.0.1',1314))
     4 server.listen()
     5 while True:
     6     conn,addr=server.accept()
     7     try:
     8         while True:
     9             data=conn.recv(1024)
    10             print('客户端发来的命令是:',data.decode())
    11             if not data:break
    12             if len(data)==0:
    13                 print('命令为空')
    14             send_data=os.popen(data.decode()).read()#执行命令,并读出结果
    15             conn.send(send_data.encode())
    16     except ConnectionResetError as e:
    17         print('一个客户端断开连接')
    18     conn.close()
    19 server.colse()
    View Code

    ssh客户端

    1 import socket
     2 client=socket.socket()
     3 client.connect(('127.0.0.1',1314))
     4 while True:
     5     data=input('>>>')
     6     if len(data)==0:continue
     7     client.send(data.encode())
     8     recv_data=client.recv(1024)
     9     print(recv_data.decode())
    10 client.close()
    View Code

    2,实现文件传输

    在前面的一个ssh做基础的情况下,我们是不是也能跟ftp一样传文件这些呢,当然可以肯定的告诉你,可以传文件的,而且在后面的学习完成以后,你还能自己写一个ftp实现上传下载文件的功能。先做一个简单的文件传输功能吧。

    服务端(server)

    1 import socket,os
     2 server=socket.socket()
     3 server.bind(('127.0.0.1',1314))
     4 server.listen()
     5 while True:
     6     conn,addr=server.accept()
     7     print('连接成功!')
     8     try:
     9         while True:
    10             file_name=conn.recv(1024).decode()
    11             if not file_name: break
    12             if os.path.isfile(file_name):#判断文件是否存在
    13                 file_len=os.stat(file_name).st_size#获取文件大小
    14                 conn.send(str(file_len).encode())
    15                 conn.recv(1024)
    16                 with open(file_name,'rb') as f:
    17                     for i in f:
    18                         conn.send(i)
    19                 print('文件发送完成')
    20             else:
    21                 print('文件不存在')
    22     except ConnectionResetError:
    23         print('一个客户端断开')
    24     finally:
    25         conn.close()
    26 server.close()
    View Code

    客户端(client)

    1 import socket
     2 client=socket.socket()
     3 client.connect(('127.0.0.1',1314))
     4 while True:
     5     file_name=input(">>>")
     6     if len(file_name)==0:continue
     7     client.send(file_name.encode())
     8     file_len=client.recv(1024).decode()
     9     client.send('接收数据长度成功'.encode())
    10     get_len=0
    11     f=open(file_name,'wb')
    12     while get_len<float(file_len):
    13         data=client.recv(1024)
    14         get_len+=len(data)
    15         f.write(data)
    16         print('已经完成',get_len,'/',file_len)
    17     print('文件传输完成')
    18     f.close()
    19 client.close()
    View Code

    二,socketserver用法

    前面都是为最后面的装逼做铺垫的,没错的,下面即将进入的是我们今天的装逼操作了,socketserver。

    当然这里我们也只是写简单的用法,其实用法跟socket用法是差不多的,所以只给了简单的使用方法

    服务端(server)

     1 import socketserver
     2 class MyServer(socketserver.BaseRequestHandler):
     3     def handle(self):#里面是跟客户端交互的全过程
     4         while True:
     5             try:
     6                 data=self.request.recv(1024) #self.request相当于socket里面的conn
     7                 print('收到来自客户端%s的消息:%s' %(self.request,data.decode()))
     8                 self.request.send(data.upper())
     9             except ConnectionResetError as e:
    10                 print('error:',e)
    11                 break
    12 if __name__ == '__main__':
    13     #创建一个服务,绑定ip跟端口
    14     server=socketserver.ThreadingTCPServer(('127.0.0.1',1314),MyServer)
    15     server.serve_forever()#服务一直开启

    客户端(client)

    1 import socket
    2 client=socket.socket()
    3 client.connect(('127.0.0.1',1314))
    4 while True:
    5     data=input('>>>')
    6     client.send(data.encode())
    7     get_data=client.recv(124)
    8     print(get_data.decode())
    9 client.close()
  • 相关阅读:
    第二十九课 循环链表的实现
    第二十八课 再论智能指针(下)
    第二十七课 再论智能指针(上)
    第二十六课 典型问题分析(Bugfix)
    普通new和placement new的重载
    leetcode 581. Shortest Unsorted Continuous Subarray
    leetcode 605. Can Place Flowers
    leetcode 219. Contains Duplicate II
    leetcode 283. Move Zeroes
    leetcode 217. Contains Duplicate
  • 原文地址:https://www.cnblogs.com/xuecaichang/p/9580448.html
Copyright © 2011-2022 走看看