一,打印机器名与 IPv4 地址
可以用python-sokect库快速地查看一些机器信息:
dang@DFL:~/test$ python3
Python 3.8.10 (default, Jun 2 2021, 10:49:15)
[GCC 10.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> host_name = socket.gethostname()
>>> print("Host name: %s" %host_name)
Host name: DFL
>>> print("IP address: %s"%socket.gethostbyname(host_name))
IP address: 127.0.1.1
>>> print("IP address: %s"%(socket.gethostbyname_ex(host_name),))
IP address: ('DFL', [], ['127.0.1.1'])
>>> print("IP address: %s"%(socket.gethostbyaddr('127.0.0.1'),))
IP address: ('localhost', [], ['127.0.0.1'])
或者在Linux中写成一个python脚本:
dang@DFL:~/test$ cat show_ip.py
import socket
def print_machine_info():
host_name = socket.gethostname()
ip_address = socket.gethostbyname(host_name)
print ("Host name: %s" %host_name)
print ("IP address: %s" %ip_address)
if __name__ == '__main__':
print_machine_info()
dang@DFL:~/test$ python3 show_ip.py
Host name: DFL
IP address: 127.0.1.1
Linux查看本机 IP 地址:
dang@DFL:~/test$ hostname
DFL
dang@DFL:~/test$ hostname -i
127.0.1.1
dang@DFL:~/test$ ifconfig
Windows10查看本机 IP 地址:
C:\Users\PC>ipconfig
C:\Users\PC>ipconfig /all
二,检索远程机器的 IP 地址
dang@DFL:~/test$ cat show_ip.py
import socket
def get_remote_machine_info(host_name):
try:
print ("IP address of %s: %s" %(host_name, socket.gethostbyname(host_name)))
except socket.error as err_msg:
print ("%s: %s" %(remote_host, err_msg))
if __name__ == '__main__':
get_remote_machine_info('www.python.org')
dang@DFL:~/test$ python3 show_ip.py
IP address of www.python.org: 151.101.76.223
- 常用
try...except 语句捕获sokect通信中出现的异常。
三,转换 IPv4 地址的格式
当处理低级网络功能时,有时一般的 IP 地址字符串表示法不是很有用,需要将它转换为 32 位二进制或者十六进制格式:
dang@DFL:~/test$ cat ip4_address_conversion.py
import socket
from binascii import hexlify
def get_remote_machine_ip4(host_name):
ip4_address = socket.gethostbyname(host_name)
try:
print("IPv4 address of %s: %s" % (host_name, ip4_address))
except socket.error as err_msg:
print("%s: %s" % (host_name, err_msg))
return ip4_address
def convert_ip4_address(host_name, mod):
mod = int(mod)
ipd_addr = get_remote_machine_ip4(host_name)
binary_ipd_addr = socket.inet_aton(ipd_addr)
if mod == 16:
hexadecimal_ip4_addr = hexlify(binary_ipd_addr)
print("Hexadecimal IPv4 Address: %s" % hexadecimal_ip4_addr)
if mod == 2:
print("Binary IPv4 address: %s" % binary_ip4_addr)
if __name__ == '__main__':
host_name = input('input host\'s name:')
base = input('input base,2 or 16:')
convert_ip4_address(host_name, base)
dang@DFL:~/test$ python3 ip4_address_conversion.py
input host's name:www.python.org
input base,2 or 16:2
IPv4 address of www.python.org: 151.101.76.223
Binary IPv4 address: b'\x97eL\xdf'
四,端口、协议和服务名称
dang@DFL:~/test$ cat find_service_name.py
import socket
def find_service_name(port, protocol):
service_name = socket.getservbyport(int(port), protocol)
print("Port: %s Protocol: %s => service name: %s" % (port, protocol, service_name))
def find_port_name(service, protocol):
port_name = socket.getservbyname(service, protocol)
print("Service: %s Protocol: %s => port name: %s" % (service, protocol, port_name))
if __name__ == '__main__':
port = input('port:')
protocol = input('protocol:')
find_service_name(port, protocol)
service = input('service:')
protocol = input('protocol:')
find_port_name(service, protocol)
dang@DFL:~/test$ python3 find_service_name.py
port:80
protocol:tcp
Port: 80 Protocol: tcp => service name: http
service:http
protocol:tcp
Service: http Protocol: tcp => port name: 80
五,转换字节序
数据在网络中以字节的形式按照一定顺序进行传输,这是网络字节序。 由于历史原因,不同CPU 处理不同的字节序,这是主机字节序。
字节序有两种类型: 1. 小端(little endian):将低序字节存储在起始地址 2. 大端(big endian):将高序字节存储在起始地址
dang@DFL:~/test$ cat byte_order_conversion.py
import socket
def convert_integer(data):
host_byte_order = socket.ntohl(data)
network_byte_order = socket.htonl(data)
print("Original: %s => Long host byte order: %s, Network byte order:% s" % (
data, host_byte_order, network_byte_order))
if __name__ == '__main__':
data = int(input("data:"))
convert_integer(data)
dang@DFL:~/test$ python3 byte_order_conversion.py
data:1234
Original: 1234 => Long host byte order: 3523477504, Network byte order:3523477504
六,套接字超时与阻塞
对一个套接字对象的读写操作默认是阻塞的,如果当前套接字还不可读/写,那么这个操作会一直阻塞下去,这就叫套接字超时; 对需要高性能的服务器来说,是不能接受的。所以,需要在进行读写操作的时候指定超时值。
dang@DFL:~/test$ cat socket_timeout.py
import socket
def socket_timeout(timeout=None):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("Default socket timeout: %s" % s.gettimeout())
print(s.getblocking())
s.settimeout(timeout)
print("Current socket timeout: %s" % s.gettimeout())
if __name__ == '__main__':
socket_timeout(timeout=100)
dang@DFL:~/test$ python3 socket_timeout.py
Default socket timeout: None
True
Current socket timeout: 100.0
dang@DFL:~/test$ cat test_socket_modes.py
import socket
def test_socket_modes():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setblocking(True)
s.settimeout(0.5)
s.bind(("127.0.0.1", 0))
socket_address = s.getsockname()
print("Trivial Server launched on socket: %s" % str(socket_address))
while 1:
s.listen(1)
if __name__ == '__main__':
test_socket_modes()
dang@DFL:~/test$ python3 test_socket_modes.py
Trivial Server launched on socket: ('127.0.0.1', 40971)
这里创建了服务器端套接字对象,看一下步骤:
- 调用
socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None) 方法通过给定的地址簇、套接字类型和协议实例化 TCP 套接字对象。 - 调用
套接字对象.socket.bind(address) 方法绑定(IP,Port)。 - 调用
套接字对象.socket.listen(\[backlog\]) 方法启动监听,等待客户端套接字连接。
什么叫套接字超时~
七,使用套接字并优雅地处理错误
在任何网络应用程序中,一端正在尝试连接,但另一方由于网络媒体故障或任何其他原因而没有响应是很常见的。 Python socket库有一种通过 socket.error 异常处理这些错误的优雅方法:
dang@DFL:~/test$ cat socket_errors.py
import sys
import socket
import argparse
def main():
parser = argparse.ArgumentParser(description='Socket Error Examples')
parser.add_argument('--host', action="store", dest="host", required=False)
parser.add_argument('--port', action="store", dest="port", type=int, required=False)
parser.add_argument('--file', action="store", dest="file", required=False)
given_args = parser.parse_args()
host = given_args.host
port = given_args.port
filename = given_args.file
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error as e:
print("Error creating socket: %s" % e)
sys.exit(1)
try:
s.connect((host, port))
except socket.gaierror as e:
print("Address-related error connecting to server: % s" % e)
sys.exit(1)
except socket.error as e:
print("Connection error: %s" % e)
sys.exit(1)
try:
msg = "GET %s HTTP/1.0\r\n\r\n" % filename
s.sendall(msg.encode('utf-8'))
except socket.error as e:
print("Error sending data: %s" % e)
sys.exit(1)
while 1:
try:
buf = s.recv(2048)
except socket.error as e:
print("Error receiving data: %s" % e)
sys.exit(1)
if not len(buf):
break
sys.stdout.write(buf.decode('utf-8'))
if __name__ == '__main__':
main()
dang@DFL:~/test$ python3 socket_errors.py --host=www.pytgo.org --port=8080 --file=1_7_socket_errors.py
Connection error: [Errno 111] Connection refused
dang@DFL:~/test$ python3 socket_errors.py --host=www.python.org --port=8080 --file=socket_errors.py
Connection error: [Errno 111] Connection refused
dang@DFL:~/test$ python3 socket_errors.py --host=www.python.org --port=80 --file=socket_errors.py
HTTP/1.1 500 Domain Not Found
Server: Varnish
Retry-After: 0
content-type: text/html
Cache-Control: private, no-cache
X-Served-By: cache-hkg17925-HKG
Content-Length: 221
Accept-Ranges: bytes
Date: Sat, 16 Oct 2021 12:17:41 GMT
Via: 1.1 varnish
Connection: close
<html>
<head>
<title>Fastly error: unknown domain </title>
</head>
<body>
<p>Fastly error: unknown domain: . Please check that this domain has been added to a service.</p>
<p>Details: cache-hkg17925-HKG</p>
</body>
</html>
这里创建了客户端套接字对象,并通过它进行了网络数据通信,简单看一下步骤:
- 调用
socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None) 方法通过给定的地址簇、套接字类型和协议实例化 TCP 套接字对象。 - 调用
套接字对象.connect(address) 方法连接到 address(host, port) 指定的远程套接字以创建套接字管道。 - 调用
套接字对象.sendall(bytes[, flags]) 方法发送数据到套接字管道。本方法持续发送字节格式的数据,直到所有数据都已发送或发生错误为止。成功后会返回 None。 - 调用
套接字对象.recv(bufsize\[, flags\]) 方法从套接字管道接收字节格式的数据。bufsize 指定一次接收的最大数据量。
python网络编程基础:网络客户端
这就是一个简单的使用套接字进行通信并处理错误的例子。
八,修改套接字发送与接受数据的缓冲区大小
在许多情况下,默认套接字缓冲区大小可能不合适,所以需要修改默认套接字缓冲区大小。 可以在套接字对象上调用 getsockopt() 和 setsockopt() 方法来分别检索和修改套接字对象的选项信息。
首先来看看socket.getsockopt(level, optname\[, buflen\]) 方法,返回该套接字对象的选项信息。参数:
- 参数均为整型数值,且 socket 库中有对应的常量定义。
- level表示选项所在的协议层级。
- optname表示需要访问的选项名。当操作套接字选项时,必须指定选项所在的层级和选项的名称。
- buflen表示缓冲区大小。
level参数说明:
常量名 | 对应值 | 说明 |
---|
SOL_IP | 0 | 在 IP 协议层级上操作选项 | SOL_SOCKET | 65535 | 在套接字API级别上操作选项 | SOL_TCP | 6 | 在 TCP 协议层级上操作选项 | SOL_UDP | 17 | 在 UDP 协议层级上操作选项 |
optname参数说明:
常量名 | 对应值 | 说明 |
---|
IP_OPTIONS | 1 | | IP_RECVDSTADDR | 25 | | IP_TOS | 3 | | IP_TTL | 4 | | SO_ACCEPTCONN | 2 | 是否是一个监听套接字。0是,1否。 | SO_BROADCAST | 32 | 设置或获取广播标志。1启用时,数据报套接字被允许发送数据包到广播地址。对面向流的套接字没有影响。 | SO_DEBUG | 1 | 是否使用调试。只允许具有CAP_NET_ADMIN能力或有效用户ID为0的进程使用。 | SO_DONTROUTE | 16 | 是否不通过网关而发送到直接连接的主机。 | SO_ERROR | 4103 | 获取套接字错误。 | SO_KEEPALIVE | 8 | 是否在面向连接的套接字上发送keep-alive消息。 | SO_LINGER | 128 | 是否延迟关闭连接 | SO_OOBINLINE | 256 | 是否将带外数据将直接放置到接收数据流中。 | SO_RCVBUF | 4098 | 设置或获取以字节为单位的最大套接字接收缓冲区,值是256的正整数倍。 | SO_RCVLOWAT | 4100 | 指定接收缓冲区最小字节数,初始值为1。 | SO_RCVTIMEO | 4102 | 指定接收超时。 | SO_REUSEADDR | 4 | 是否允许重用本地地址和端口。 | SO_SNDBUF | 4097 | 设置或获取以字节为单位的最大套接字发送缓冲区,值是2048的正整数倍。 | SO_SNDLOWAT | 4099 | 指定发送缓冲区最小字节数,初始值为1。 | SO_SNDTIMEO | 4101 | 指定发送超时。 | SO_TYPE | 4104 | 获取套接字类型。 | TCP_FASTOPEN | 15 | 是否开启TCP快速握手特性 | TCP_KEEPCNT | 16 | TCP在放弃连接之前应该发送的最大keepalive探测数。 | TCP_KEEPIDLE | 3 | 在socket设置SO_KEEPALIVE选项后,设置TCP在开始发送keepalive探测之前需要保持空闲的时间,单位为秒。 | TCP_KEEPINTVL | 17 | 设置每个keepalive探测之间的时间,单位为秒。 | TCP_MAXSEG | 4 | 设置TCP最大数据段的大小 | TCP_NODELAY | 1 | 是否不使用Nagle算法 |
optname参数说明:socket(7) — Linux manual page getsockopt(2) — Linux manual page
再看看socket.setsockopt(level, optname, value: buffer) 方法,参数说明同上。
dang@DFL:~/test$ cat modify_buff_size.py
import socket
SEND_BUF_SIZE = 4096
RECV_BUF_SIZE = 4096
def modify_buff_size():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sndbufsize = sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF)
print("send buffer size [Before]:%d" % sndbufsize)
rcvbufsize = sock.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF)
print("receive buffer size [Before]:%d" % rcvbufsize)
sock.setsockopt(
socket.SOL_TCP,
socket.TCP_NODELAY,
1)
sock.setsockopt(
socket.SOL_SOCKET,
socket.SO_SNDBUF,
SEND_BUF_SIZE)
sock.setsockopt(
socket.SOL_SOCKET,
socket.SO_RCVBUF,
RECV_BUF_SIZE)
sndbufsize = sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF)
print("send buffer size [After]:%d" % sndbufsize)
rcvbufsize = sock.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF)
print("receive buffer size [After]:%d" % rcvbufsize)
if __name__ == '__main__':
modify_buff_size()
dang@DFL:~/test$ python3 modify_buff_size.py
send buffer size [Before]:16384
receive buffer size [Before]:131072
send buffer size [After]:8192
receive buffer size [After]:8192
九,服务器端重用socket地址
一般情况下,在特定端口上运行 Python 套接字服务器并尝试在关闭一次后重新运行它时,将无法使用相同的端口:
Traceback (most recent call last):
File "reuse_socket_address.py",
line 40, in <module>
reuse_socket_addr()
File "reuse_socket_address.py",
line 25, in reuse_socket_addr
srv.bind( ('', local_port) )
File "<string>", line 1, in bind
socket.error: [Errno 98] Address
already in use
解决此问题的方法是调用启用套接字选项 SO_REUSEADDR : 服务器端创建套接字对象后,查询地址重用的状态。 然后调用setsockopt() 方法来更改其地址重用状态的值。 最后按照通常的步骤绑定socket地址并侦听客户端连接。
这里假设我们运行前面的test_socket_modes()函数来创建一个服务器端套接字,按下 ctrl+c 后报错如下:
dang@DFL:~/test$ python3 test_socket_modes.py
Trivial Server launched on socket: ('127.0.0.1', 40971)
^C
Traceback (most recent call last):
File "test_socket_modes.py", line 19, in <module>
test_socket_modes()
File "test_socket_modes.py", line 15, in test_socket_modes
s.listen(1)
KeyboardInterrupt
这表明在程序执行过程中被键盘中断了执行。我们可以捕获 KeyboardInterrupt 异常,则再按下 ctrl+c 后,Python 脚本就会终止而不显示任何异常消息。
服务器端重用地址并捕获 KeyboardInterrupt 异常:
dang@DFL:~/test$ cat reuse_socket_addr.py
import socket
def reuse_socket_addr():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
old_state = sock.getsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR)
print("Old sock state: %s" % old_state)
sock.setsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR,
1)
new_state = sock.getsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR)
print("New sock state: %s" % new_state)
local_port = 8282
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.setsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR,
1)
srv.bind(('127.0.0.1', local_port))
srv.listen(1)
print("Listening on port: %s " % local_port)
while True:
try:
connection, addr = srv.accept()
print('Connected by %s:%s' % (addr[0], addr[1]))
ret = connection.recv(1024)
ret = ret.decode("gbk")
print(ret)
except KeyboardInterrupt:
break
except socket.error as msg:
print('%s' % (msg,))
if __name__ == '__main__':
reuse_socket_addr()
dang@DFL:~/test$ python3 reuse_socket_addr.py
Old sock state: 0
New sock state: 1
Listening on port: 8282
Connected by 127.0.0.1:34598
Received from client: 你好服务端,我是客户端小黑!
Connected by 127.0.0.1:34600
Received from client: 你好服务端,我是客户端小黑!
这个服务器端程序比前面的哪个稍微完整了一些:
- 创建套接字。
- 调用
套接字对象.etsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 方法允许端地址用。 - 绑定地址。
- 监听连接。
- 调用
套接字对象.accept() 方法接受连接。此 socket 必须绑定到一个地址上并且监听连接。返回值是一个 (conn, address) 对: conn 表示新的套接字对象,用于在此连接上收发数据,address 表示连接另一端的套接字所绑定的地址。 - 调用
新的套接字对象.recv(bufsize\[, flags\]) 方法从新的套接字接收数据。返回一个字节对象来表示接收到的数据。bufsize 指定一次接收的最大数据量。
python网咯编程基础:网络服务器
十,UDP 客户端从互联网时间服务器打印当前时间
许多程序依赖于准确的机器时间,例如 UNIX 中的 make 命令,这就需要与网络中的另一个时间服务器同步,可以为此编写一个 Python 函数:
dang@DFL:~/test$ python-pip install ntplib
python-pip:未找到命令
dang@DFL:~/test$ pip install ntplib
Collecting ntplib
Downloading ntplib-0.4.0-py2.py3-none-any.whl (6.8 kB)
Installing collected packages: ntplib
Successfully installed ntplib-0.4.0
dang@DFL:~/test$ cat print_time.py
import ntplib
from time import ctime
def print_time():
ntp_client = ntplib.NTPClient()
response = ntp_client.request('0.cn.pool.ntp.org')
print(ctime(response.tx_time))
if __name__ == '__main__':
print_time()
dang@DFL:~/test$ python3 print_time.py
Sun Oct 17 19:14:15 2021
有时,又不需要从 NTP 服务器获取精确时间,则可以使用更简单的被称为简单网络时间协议SNPT 的 NTP 版本。 首先定义两个常量:NTP_SERVER 和 TIME1970。前者表示客户端将连接到的服务器地址,后者表示参考时间 1970 年 1 月 1 日。可以在http://www.epochconverter.com/找到参考时间的值或转换为参考时间。 然后客户端使用SOCK_DGRAM 选项创建一个 UDP 套接字以按照 UDP 协议连接到服务器。 然后客户端需要在数据包中发送 SNTP 协议数据 (’\x1b’ 47 * ‘\0’),并使用 和 recvfrom() 方法发送和接收数据。 然后,客户端需要一个专门的 struct 库来解包服务器以打包数组的形式返回时间信息。 唯一有趣的数据位于数组的第 11 个元素中。 最后,我们需要从解压后的值中减去参考时间值 TIME1970 以获得实际的当前时间。
dang@DFL:~/test$ cat print_time.py
import socket
import struct
import time
NTP_SERVER = "cn.pool.ntp.org"
TIME1970 = 2208988800
def print_time():
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
data = '\x1b' + 47 * '\0'
client.sendto(data.encode('utf-8'), (NTP_SERVER, 123))
data, address = client.recvfrom(1024)
if data:
print('Response received from:', address)
t = struct.unpack('!12I', data)[10]
t -= TIME1970
print('\tTime=%s' % time.ctime(t))
if __name__ == '__main__':
print_time()
dang@DFL:~/test$ python3 print_time.py
Response received from: ('5.79.108.34', 123)
Time=Sun Oct 17 19:19:18 2021
十一,编写一个简单的 TCP 回显客户端/服务器端应用
服务器将回显它从客户端接收到的任何内容,将使用 Python argparse 模块从命令行指定 TCP 端口。 服务器和客户端脚本都将采用此参数。
- 首先,创建服务器 TCP 套接字对象,并设置重用地址,以便我们可以根据需要多次运行服务器。
- 将服务器套接字绑定到本地机器上的给定端口。 在侦听阶段,我们确保使用 listen() 方法的 backlog参数侦听队列中的多个客户端。
- 最后,等待客户端连接并发送一些数据到服务器。 当接收到数据时,服务器将数据回显给客户端。
dang@DFL:~/test$ cat echo_server.py
import socket
import argparse
host = 'localhost'
data_payload = 2048
backlog = 5
def echo_server(port):
""" 一个简单的回显服务器 """
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR,
1)
server_address = (host, port)
print("启动回显服务器 %s:%s" % server_address)
sock.bind(server_address)
sock.listen(backlog)
while True:
print("等待从客户端接收信息...")
client, address = sock.accept()
data = client.recv(data_payload)
if data:
print("接收到的客户端数据为: %s" % data.decode('gbk'))
client.send(data)
print("已将该 %s 字节串返回给 %s" % (data, address))
client.close()
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Socket Server Example')
parser.add_argument('--port', action="store", dest="port", type=int, required=True)
given_args = parser.parse_args()
port = given_args.port
echo_server(port)
dang@DFL:~/test$ python3 echo_server.py --port=9900
启动回显服务器 localhost:9900
等待从客户端接收信息...
接收到的客户端数据为: 测试数据,该信息会被回显!
已将该 b'\xb2\xe2\xca\xd4\xca\xfd\xbe\xdd\xa3\xac\xb8\xc3\xd0\xc5\xcf\xa2\xbb\xe1\xb1\xbb\xbb\xd8\xcf\xd4\xa3\xa1' 字节串返回给 ('127.0.0.1', 57516)
等待从客户端接收信息...
dang@DFL:~/test$ cat echo_client.py
import socket
import argparse
host = 'localhost'
def echo_client(port):
""" 一个简单的回显客户 """
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = (host, port)
print("正在连接到 %s:%s" % server_address)
sock.connect(server_address)
try:
message = "测试数据,该信息会被回显!"
print("正在发送 %s" % message)
sock.sendall(message.encode('gbk'))
amount_received = 0
amount_expected = len(message)
while amount_received < amount_expected:
data = sock.recv(2018)
amount_received += len(data)
print("接收到的服务器端数据为: %s" % data.decode('gbk'))
except socket.error as e:
print("Socket 错误: %s" % str(e))
except Exception as e:
print("其他错误: %s" % str(e))
finally:
print("正在关闭到服务器端的链接...")
sock.close()
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Socket Server Example')
parser.add_argument('--port', action="store", dest="port", type=int, required=True)
given_args = parser.parse_args()
port = given_args.port
echo_client(port)
dang@DFL:~/test$ python3 echo_client.py --port=9900
正在连接到 localhost:9900
正在发送 测试数据,该信息会被回显!
接收到的服务器端数据为: 测试数据,该信息会被回显!
正在关闭到服务器端的链接...
一个简单的基于TCP通信的服务器端与客户端程序
|