1、Socket(也称套接字)介绍

socket这个东东干的事情,就是帮你把tcp/ip协议层的各种数据封装啦、数据发送、接收等通过代码已经给你封装好了

,你只需要调用几行代码,就可以给别的机器发消息了。

参考https://www.cnblogs.com/weizhixiang/p/6298523.html

2、套接字

所谓socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。应用程 
序通常通过"套接字"向网络发出请求或者应答网络请求。

套接字可以根据通信性质分类,这种性质对于用户是可见的。应用程序一般仅在同一类的 
套接字间进行通信。不过只要底层的通信协议允许,不同类型的套接字间也照样可以通信。套 
接字有两种不同的类型:流套接字和数据报套接字。

3、套接字的工作原理

要通过互联网进行通信,你至少需要一对套接字,其中一个运行于客户机端,我们称之为 
ClientSocket,另一个运行于服务器端,我们称之为ServerSocket。 
    根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个 
步骤:服务器监听,客户端请求,连接确认。

所谓服务器监听,是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的 
状态,实时监控网络状态。 
    所谓客户端请求,是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接 
字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的 
地址和端口号,然后就向服务器端套接字提出连接请求。 
    所谓连接确认,是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它 
就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦 
客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他 
客户端套接字的连接请求。

4、网络编程的解释

网络编程的目的就是指直接或间接地通过网络协议与其他计算机进行通讯。网络编程中 
有两个主要的问题,一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后 
如何可靠高效的进行数据传输。在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的 
路由,由IP地址可以唯一地确定Internet上的一台主机。而TCP层则提供面向应用的可靠的 
或非可靠的数据传输机制,这是网络编程的主要对象,一般不需要关心IP层是如何处理数据 
的。

目前较为流行的网络编程模型是客户机/服务器(C/S)结构。即通信双方一方作为服务 
器等待客户提出请求并予以响应。客户则在需要服务时向服务器提出申请。服务器一般作为 
守护进程始终运行,监听网络端口,一旦有客户请求,就会启动一个服务进程来响应该客 
户,同时自己继续监听服务端口,使后来的客户也能及时得到服务。

在Internet上IP地址和主机名是一一对应的,通过域名解析可以由主机名得到机器的IP, 
由于机器名更接近自然语言,容易记忆,所以使用比IP地址广泛,但是对机器而言只有IP地 
址才是有效的标识符。

通常一台主机上总是有很多个进程需要网络资源进行网络通讯。网络通讯的对象准确的讲 
不是主机,而应该是主机中运行的进程。这时候光有主机名或IP地址来标识这么多个进程显然 
是不够的。端口号就是为了在一台主机上提供更多的网络资源而采取得一种手段,也是TCP层 
提供的一种机制。只有通过主机名或IP地址和端口号的组合才能唯一的确定网络通讯中的对象: 
进程。

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。

在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部。

5、编写Socket套接字的流程

1、服务器端程序的编写步骤:

(1)创建调用socket()函数创建一个用于通信的套接字。#phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

(2)s.bind() 绑定(主机,端口号)到套接字。 #phone.bind(('127.0.0.1',8080))

(3)s.listen() 开始TCP监听 。#phone.listen(5)# 5 代表最多挂机数

(4)s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来。#  conn,client_addr = phone.accept()

(5)处理客户端的连接请求。 # 1、s.recv() 接收数据 /data = conn.recv(1024) # 2、反馈给客户端:s.send() 发送数据

(6)关闭套接字/  s.send() 发送数据

2、客户端程序的编写步骤:

(1)调用socket()函数创建一个用于通信的套接字。# phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

(2)s.connect() 主动初始化TCP服务器连接 # phone.connect(('127.0.0.1',8080))

(3)调用读写函数发送或者接收数据。# s.send() 发送数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完,可后面通过实例解释)

例如:phone.send('hello'.encode('utf-8'))

(4)接受服务端的反馈信息: s.recv() 接收数据 # 例如:
data = phone.recv(1024)
(5)关闭sokect

参考:https://www.cnblogs.com/lixiaoliuer/p/6543968.html
② server.bind(address)

  server.bind(address) 将套接字绑定到地址。address地址的格式取决于地址族。在AF_INET下,以元组(host,port)的形式表示地址

③ server.listen(backlog)

  开始监听传入连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量。backlog等于5,表示内核已经接到了连接请求,但服务器还没有调用accept进行处理的连接个数最大为5,这个值不能无限大,因为要在内核中维护连接队列

④ server.setblocking(bool)

  是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错

⑤ conn,addr = server.accept() 

  接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。接收TCP 客户的连接(阻塞式)等待连接的到来

⑥ client.connect(address)

  连接到address处的套接字。一般,address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。

⑦ client.connect_ex(address)

  同上,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回编码,例如:10061

⑧ client.close()

  关闭套接字

⑨ client.recv(bufsize[,flag])

  接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。flag提供有关消息的其他信息,通常可以忽略

⑩ client.recvfrom(bufsize[.flag])

  与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址

⑪ server.send(string[,flag])

  将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。即:可能未将指定内容全部发送

⑫ server.sendall(string[,flag])  

  将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常;

      内部通过递归调用send,将所有内容发送出去

⑬ server.sendto(string[,flag],address)

  将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。该函数主要用于UDP协议

⑭ sk.settimeout(timeout)

  设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如 client 连接最多等待5s )

⑮ sk.getpeername()

  返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)

⑯ sk.getsockname()

  返回套接字自己的地址。通常是一个元组(ipaddr,port)

⑰ sk.fileno()

  套接字的文件描述符

6、代码实例

6.1、简单的套接字通信

服务端和客户端在一个IDE下

服务端:

import socket

# 1 买手机
# phone 为套接字对象
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#(sock_stream 流)
# 2 绑定手机卡,127.0.0.1是回送地址,指本地机,一般用来测试使用。客户端、服务端在一台主机上
phone.bind(('127.0.0.1',8081))# 端口 0-65535:0-1024给操作系统使用 # 3 开机
phone.listen(5)# 5 代表最多挂机数 # 4 等电话连接 # 在同一个IDE上执行客户端、服务端,,先执行服务端后,在执行客户端
# 直接执行客户端会发生错误
print('------starting-------')
conn,client_addr = phone.accept() # accept()对于 connect()做的3次握手
# print('==========>')
# print(res) # 5 收、发消息
data = conn.recv(1024) # 1024个字节 代表接受数据最大数,,单位bytes字节
print('客户端数据',data) conn.send(data.upper()) # 服务端回数据给客户端
# 6 挂电话
conn.close() # 7 关机
phone.close()

客户端:

import socket

# 1 买手机
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#(sock_stream 流) # 2 拨号,127.0.0.1是回送地址,指本地机,一般用来测试使用。客户端、服务端在一台主机上
phone.connect(('127.0.0.1',8081))# 端口 0-65535:0-1024给操作系统使用 # 3 发、收 消息
phone.send('hello'.encode('utf-8'))
data = phone.recv(1024)
print(data)
# 4 关闭
phone.close()

服务端先执行,一直开着,然后再执行客户端

6.2、加上链接循环

6.3、简单的远程执行命令程序开发

#-----------windows-----------------
#dir:查看某一个文件夹下的子文件名与子文件夹名
#ipconfig:查看本地网卡的ip信息
#tasklist:查看运行的进程 #----------linux---------------:
#ls
#ifconfig
#ps aux #执行系统命令,并且拿到命令的结果
# import os
# res=os.system('xxxxlxxxs /')
# print('命令的结果是:',res) import subprocess
obj=subprocess.Popen('xxxxxxls /',shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE) print(obj)
print('stdout 1--->: ',obj.stdout.read().decode('utf-8'))
# print('stdout 2--->: ',obj.stdout.read().decode('utf-8'))
#print('stderr 1--->: ',obj.stderr.read().decode('utf-8'))

服务端:

import socket
import subprocess phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',9901)) #0-65535:0-1024给操作系统使用
phone.listen(5) print('starting...')
while True: # 链接循环
conn,client_addr=phone.accept()
print(client_addr) while True: #通信循环
try:
#1、收命令
cmd=conn.recv(1024)
if not cmd:break #适用于linux操作系统 #2、执行命令,拿到结果
obj = subprocess.Popen(cmd.decode('utf-8'), shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE) stdout=obj.stdout.read()
stderr=obj.stderr.read() #3、把命令的结果返回给客户端
print(len(stdout)+len(stderr))
conn.send(stdout+stderr) #+是一个可以优化的点 except ConnectionResetError: #适用于windows操作系统
break
conn.close() phone.close()

客户端:

import socket

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

phone.connect(('127.0.0.1',9901))

while True:
#1、发命令
cmd=input('>>: ').strip() #ls /etc
if not cmd:continue
phone.send(cmd.encode('utf-8')) #2、拿命令的结果,并打印
data=phone.recv(1024)
print(data.decode('gbk'))# window用gbk phone.close()

 



19 网络编程--Socket 套接字方法的更多相关文章

  1. 19、网络编程 (Socket套接字编程)

    网络模型 *A:网络模型 TCP/IP协议中的四层分别是应用层.传输层.网络层和链路层,每层分别负责不同的通信功能,接下来针对这四层进行详细地讲解. 链路层:链路层是用于定义物理传输通道,通常是对某些 ...

  2. 网络编程--Socket(套接字)

    网络编程 网络编程的目的就是指直接或间接地通过网络协议与其他计算机进行通讯.网络编程中 有两个主要的问题,一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后 如何可靠高效的进行数据传输.在 ...

  3. 8.7 day28 网络编程 socket套接字 半连接池 通信循环 粘包问题 struct模块

    前置知识:不同计算机程序之间的数据传输 应用程序中的数据都是从程序所在计算机内存中读取的. 内存中的数据是从硬盘读取或者网络传输过来的 不同计算机程序数据传输需要经过七层协议物理连接介质才能到达目标程 ...

  4. python网络编程-socket套接字通信循环-粘包问题-struct模块-02

    前置知识 不同计算机程序之间数据的传输 应用程序中的数据都是从程序所在计算机内存中读取的. 内存中的数据是从硬盘读取或者网络传输过来的 不同计算机程序数据传输需要经过七层协议物理连接介质才能到达目标程 ...

  5. TCP/IP网络编程之网络编程和套接字

    网络编程和套接字 网络编程又称为套接字编程,就是编写一段程序,使得两台连网的计算机彼此之间可以交换数据.那么,这两台计算机用什么传输数据呢?首先,需要物理连接,将一台台独立的计算机通过物理线路连接在一 ...

  6. Linux网络编程——原始套接字实例:MAC 头部报文分析

    通过<Linux网络编程——原始套接字编程>得知,我们可以通过原始套接字以及 recvfrom( ) 可以获取链路层的数据包,那我们接收的链路层数据包到底长什么样的呢? 链路层封包格式 M ...

  7. 【TCP/IP网络编程】:01理解网络编程和套接字

    1.网络编程和套接字 网络编程与C语言中的printf函数和scanf函数以及文件的输入输出类似,本质上也是一种基于I/O的编程方法.之所以这么说,是因为网络编程大多是基于套接字(socket,网络数 ...

  8. UNIX网络编程——原始套接字(dos攻击)

    原始套接字(SOCK_RAW).应用原始套接字,我们可以编写出由TCP和UDP套接字不能够实现的功能. 注意原始套接字只能够由有 root权限的人创建. 可以参考前面的博客<<UNIX网络 ...

  9. UNIX网络编程——原始套接字的魔力【续】

    如何从链路层直接发送数据帧 上一篇里面提到的是从链路层"收发"数据,该篇是从链路层发送数据帧. 上一节我们主要研究了如何从链路层直接接收数据帧,可以通过bind函数来将原始套接字绑 ...

随机推荐

  1. jquery.ellipsis根据宽度(不是字数)进行内容截断,支持多行内容

    jquery.ellipsis 自动计算内容宽度(不是字数)截断,并加上省略号,内容不受中英文或符号限制. 如果根据字数来计算的话,因为不同字符的宽度并不相同,比如l和W,特别是中英文,最终内容宽度会 ...

  2. 【转】每天一个linux命令(23):Linux 目录结构

    原文网址:http://www.cnblogs.com/peida/archive/2012/11/21/2780075.html 对于每一个Linux学习者来说,了解Linux文件系统的目录结构,是 ...

  3. 字符设备之register_chrdev与register_chrdev_region(转)

    之前写字符设备驱动,都是使用register_chrdev向内核注册驱动程序中构建的file_operations结构体,之后创建的设备文件,只要是主设备号相同(次设备号不同),则绑定的都是同一个fi ...

  4. Kindle一周使用感受

    为何选择Kindle 「Kindle」终于入手,心情十分愉悦^_^,入手的是499块「Kindle国行版」,个人感觉电子墨水屏显示效果很赞,很适合在光线比较充足的环境下阅读,即使在中午的阳光底下使用K ...

  5. JS怎么把字符串数组转换成整型数组

    今天在学习highcharts时,遇到了一个把字符串数组转换为整形数组的问题,拿在这里讨论一下: 比如有一个字符串: var dataStr="1,2,3,4,5"; 现在需要把它 ...

  6. mysql九大类常用函数

    一.数学函数 ABS(x) 返回x的绝对值BIN(x) 返回x的二进制(OCT返回八进制,HEX返回十六进制)CEILING(x) 返回大于x的最小整数值EXP(x) 返回值e(自然对数的底)的x次方 ...

  7. python中的with

    看例 """ 需求:不用数据库连接池,实现数据库链接操作 """ class SQLHelper(object): def open(sel ...

  8. Pascal可视化编程 CodeTyphon 、Lazarus

    CodeTyphon是一个免费的Pascal语言可视化编程工作室软件包,基于Free Pascal和Lazarus.相当于Delphi 的RAD Studio. CodeTyphon支持多平台开发,包 ...

  9. 关于 ake sure class name exists, is public, and has an empty constructor that is public

    解决方法:自定义的fragment最好有一个Public的参数为空的构造函数,若需要传入一个参数,可以使用下面的方法 public FileViewFragment(){ } public stati ...

  10. php array_flip() 删除数组重复元素——大彻大悟

    1. php array_flip() 删除数组重复元素,如果用于一维索引数组,好理解. [root@BG-DB:~]$more arr.php  <?php         $arr = ar ...