Network (socket) programming

First, the network protocol

The client / server architecture

1. Hardware C / S architecture (printer)

2. Software C / S architecture (Internet everywhere is C / S structure): B / S architecture is C / S structure of one kind, B / S browser / server

Relations C / S architecture and socket: We use socket is to complete the C / S architecture development

osi seven

Introduction:

Notice a complete computer system is composed of hardware, operating system, application software composed of three, with the three conditions, one computer system can themselves play with myself (to make a stand-alone game, playing a demining Han)

If you're going to play with other people, then you need to get online, what is the Internet?

The core of the Internet is a bunch of protocols, protocol is the standard, such as standard human communications around the world in English

If the computer than Zuoren, English Internet Protocol is the computer industry. All computers have learned to Internet protocol, that all computers will be in accordance with uniform standards to send and receive information to complete the communication.

According to the division of different people use the Internet protocol hierarchy logically divided,

See Network Communication Theory: http: //www.cnblogs.com/linhaifeng/articles/5937962.html

Why learn socket must first learn Internet Protocol?

  First, C / S architecture is network-based communication

  Then the core network that is a bunch of network protocol, which is the standard protocol. If you want to develop a software-based network communication, you must follow these standards

socke layer

Second, what socket that?

The socket is an application layer and the TCP / IP communication protocol middleware abstraction layer, which is a set of interfaces. In design mode, Socket is actually a facade pattern, it is the complexity of TCP / IP protocol suite is hidden behind the Socket interface for users, a simple interface is all set, let Socket to organize data in order to comply with the specified protocol.

So, we do not need in-depth understanding of tcp / udp protocol, socket has a good package for us, we just need to follow the provisions of the socket to program, write a program that follows the natural tcp / udp standards.

Third, based on the TCP protocol socket

Sockets Category:

基于文件类型的套接字家族:AF_UNIX(在Unix系统上,一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程同时运行在同一机器,可以通过访问同一个文件系统间接完成通信)

 基于网络类型的套接字家族:AF_INET  (python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我们只使用AF_INET)

套接字的工作流程:

下面我们举个打电话的小例子来说明一下

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

(如果你去一家餐馆吃饭,假设哪里的老板就是服务端,而你自己就是客户端,当你去吃饭的时候,你肯定的知道那个餐馆,也就是服务端的地址吧,但是对于你自己来说,餐馆的老板不需要知道你的地址吧)

套接字函数

  1 import socket
  2 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  3 # 1.服务端套接字函数
  4 phone.bind('主机ip地址',端口号)  #绑定到(主机,端口号)套接字
  5 phone.listen() #开始TCP监听
  6 phone.accept() #被动接受TCP客户的连接,等待连接的到来
服务端套接字函数 View Code

 

  1 import socket
  2 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#买手机
  3 phone.connect()  #主动连接服务端的ip和端口
  4 phone.connect_ex()  #connect()函数的扩展版本,出错的时候返回错码,而不是抛出异常
客户端套接字函数 View Code

 

  1 phone.recv() #接受TCP数据
  2 phone.send() #发送TCP数据
  3 phone.recvfrom() #接受UDP数据
  4 phone.sendto() #发送UDP数据
  5 phone.getpeername() #接收到当前套接字远端的地址
  6 phone.getsockname() #返回指定套接字的参数
  7 phone.setsockopt() #设置指定套接字的参数
  8 phone.close() #关闭套接字
  9 
3.服务端和客户端的公共用途的嵌套字函数 View Code

 

  1 phone.setblocking()  #设置套接字的阻塞与非阻塞模式
  2 phone.settimeout()  #设置阻塞套接字操作的超时时间
  3 phone.gettimeout()  #得到阻塞套接字操作的超时时间
面向锁的套接字方法 View Code

 

  1 phone.fileno()  # 套接字的文件描述符
  2 phone.makefile() #创建一个与该套接字相关的文件
面向文件的套接字函数 View Code

 

TCP是基于链接的,必须先启动服务器,然后再启动客户端去链接服务端

服务端:

  1 import socket
  2 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#买手机
  3 phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #可以多次启动
  4 #执行多次的时候会报错,那么怎么办呢、?就在绑卡前面加上上面那句setsockopt方法就ok了
  5 phone.bind(('192.168.20.44',8080))#绑定手机卡(ip,端口)
  6 # 端口号在1024以前的是系统用的,1024以后的都是你自己写的程序去定义的端口
  7 
  8 print('starting run......')
  9 phone.listen(5) #开机   5代表的是最多挂起5个,也可以好多个
 10 while True: #链接循环
 11     coon,client_addr=phone.accept()#等待接电话,(coon是建立的链接,客户端的ip和端口号组成的元组)
 12     print(coon,client_addr)
 13 
 14     #收发消息
 15     while True:  #通信循环
 16         try:  #如果不加try...except ,就会报错,因为它不知道你什么时候断开链接的,服务器还以为你在运行
 17             data = coon.recv(1024) #收了1024个字节的消息
 18             print('client data 收到消息:%s'%data.decode('utf-8'))
 19             coon.send(data.upper())  #发消息
 20         except Exception:  #因为你不知道客户端什么时候断开链接,
 21             break
 22     coon.close() #挂电话
 23 phone.close() #关机
 24 
 25 
 26 # 处理逻辑错误的两种方式:
 27     # if 判断
 28     # try...except 异常处理
 29 # 异常处理
 30 # 当你知道直接错误的条件时就用if判断了
 31 # 当程序错误一定发生,但是你又预知不了它出错的条件是什么的时候,就用try...except
 32 
 33 服务端
服务端 View Code

客户端:

  1 import socket
  2 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#买手机
  3 phone.connect(('192.168.20.44',8080))  #直接连接服务端的ip和端口
  4 
  5 # 发收消息
  6 while True:
  7     msg = input('>>:').strip()  #用户输入
  8     if not msg:continue  #如果为空就继续输
  9     phone.send(msg.encode('utf-8'))  #  发送你输入的消息
 10     # phone.send('hello'.encode('utf-8'))
 11     data = phone.recv(1024)  #在接收一下
 12     print('server back res服务端返回结果:>>%s'%data.decode('utf-8'))
 13 
 14 phone.close()
 15 
 16 
客户端 View Code

注意:

如果你在重启服务端的时候可能遇到这样的问题:

这个是由于你的服务端仍然存在四次挥手的time_wait状态在占用地址(如果不懂,请深入研究1.tcp三次握手,四次挥手 2.syn洪水攻击 3.服务器高并发情况下会有大量的time_wait状态的优化方法)。那么怎么解决呢?你也可以这样的

  1 #加入一条socket配置,重用ip和端口
  2 
  3 phone=socket(AF_INET,SOCK_STREAM)
  4 phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
  5 phone.bind(('127.0.0.1',8080))

四、基于TCP协议模拟ssh远程执行命令

  1 import socket
  2 import subprocess
  3 phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#买手机
  4 phone.bind(('192.168.20.44',8081))#绑定手机卡
  5 phone.listen(5)#阻塞的最大个数
  6 print('starting....')
  7 while True:
  8     conn,addr=phone.accept()#等待连接
  9     print(addr,conn)
 10     while True:
 11         cmd=conn.recv(10240)#接收的最大值
 12         # if not cmd :break
 13         print('接收的是:%s'%cmd.decode('utf-8'))
 14         #处理过程
 15         res=subprocess.Popen(cmd.decode('utf-8'),shell=True,   #Popen是执行命令的方法
 16                              stdout=subprocess.PIPE,
 17                              stderr=subprocess.PIPE )
 18         stdout=res.stdout.read()
 19         stuerr=res.stderr.read()
 20         conn.send(stdout+stuerr)
 21     conn.close()
 22 phone.close()
 23 
 24 
服务端 View Code
  1 import socket
  2 
  3 phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  4 phone.connect(('192.168.20.44',8081))#绑定端口
  5 while True:
  6     cmd=input('>>请输入').strip()
  7     if  not cmd: continue
  8     phone.send(cmd.encode('utf-8'))
  9     data=phone.recv(10240)
 10     print('返回的是%s'%data.decode('gbk'))
 11 phone.close()
 12 
 13 
客户端 View Code

    基于UDP协议的socket

  1 from socket import *
  2 udp_server = socket(AF_INET,SOCK_DGRAM)
  3 udp_server.bind(('127.0.0.1',8080)) #绑定
  4 while True:#通讯循环
  5     msg,client_addr= udp_server.recvfrom(1024)
  6     print('收到的消息是:%s'%msg.decode('utf-8'))
  7     udp_server.sendto(msg.upper(),client_addr)
  8 udp_server.close()
  9 
 10 
服务端 View Code
  1 # udp 无链接,所以不需要连接
  2 from socket import *
  3 udp_client = socket(AF_INET,SOCK_DGRAM)
  4 
  5 while True:
  6     msg = input('>>:').strip()
  7     udp_client.sendto(msg.encode('utf-8'),('127.0.0.1',8080))
  8     res,sever_addr = udp_client.recvfrom(1024)
  9     print('返回的结果是:%s'%res.decode('utf-8'))
 10 udp_client.close()
 11 
 12 
客户端 View Code

    基于UDP协议的socket的应用(模拟QQ聊天)

  1 from socket import *
  2 udp_server= socket(AF_INET,SOCK_DGRAM)
  3 udp_server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
  4 udp_server.bind(('127.0.0.1',8080))
  5 print('start running...')
  6 
  7 while True:
  8     qq_msg,addr = udp_server.recvfrom(1024)
  9     print('来自[%s:%s]的一条消息:\033[44m%s\033[0m'%(addr[0],addr[1],qq_msg.decode('utf-8')))
 10     back_msg = input('回复消息:>>').strip()
 11     udp_server.sendto(back_msg.encode('utf-8'),addr)
 12 udp_server.close()
 13 
 14 
服务端 View Code
  1 from socket import *
  2 udp_client = socket(AF_INET,SOCK_DGRAM)
  3 qq_name_dic = {
  4     '房得成':('127.0.0.1',8080),
  5     '陈凤琴':('127.0.0.1',8080),
  6     '王雅玲':('127.0.0.1',8080),
  7     '喜洋洋':('127.0.0.1',8080)
  8 }
  9 while True:
 10     qq_name = input('请输入聊天对象:>>').strip()
 11     if qq_name not in qq_name_dic: continue
 12     while True:
 13         msg = input('请输入消息,回车发送:').strip()
 14         if msg=='quit':break
 15         if not msg or not qq_name or qq_name not in qq_name_dic:continue
 16         udp_client.sendto(msg.encode('utf-8'),qq_name_dic[qq_name])
 17         back_msg,addr = udp_client.recvfrom(1024)
 18         print('来自[%s:%s]的一条消息:\033[41m%s\033[0m'%(addr[0],addr[1],back_msg.decode('utf-8')))
 19 udp_client.close()
 20 
客户端 View Code

运行结果截图:

五、subprocess子进程模块

  1 import subprocess
  2 #Popen方法是用来执行系统命令的,直接把结果打印到终端了
  3 res =subprocess.Popen(r'dir',shell=True,
  4                        #r'dsfsdfr',shell=True,
  5                       # stdin= #标准输入(不常用)
  6                        stdout=subprocess.PIPE,#stdout 标准输出
  7                        stderr=subprocess.PIPE) #stderr 标准错误
  8 # 拿到的是‘gbk’编码的结果,
  9 # 这个命令可能有正确结果,也可能有错误结果
 10 print(res.stdout.read().decode('gbk'))
 11 print('========')
 12 print(res.stdout.read().decode('gbk'))  #说明只能读一次
 13 print(res.stderr.read().decode('gbk'))  #如果是错误的就会提示
 14 
 15 
subprocess View Code

 

六、struct模块

  1 #该模块可以把一个类型,如数字,转成固定长度的bytes类型
  2 import struct
  3 # res = struct.pack('i',12345)
  4 # print(res,len(res),type(res))  #长度是4
  5 
  6 res2 = struct.pack('i',12345111)
  7 print(res2,len(res2),type(res2))  #长度也是4
  8 
  9 unpack_res =struct.unpack('i',res2)
 10 print(unpack_res)  #(12345111,)
 11 # print(unpack_res[0]) #12345111
 12 
 13 
struct View Code

 

 

归类 :  网络编程socket

Guess you like

Origin www.cnblogs.com/lz1996/p/11574187.html