【问题标题】:Making an outbound connection建立出站连接
【发布时间】:2020-06-03 04:52:53
【问题描述】:

我最近一直在修补 python 套接字模块,但遇到了一个问题。 这是我的python服务器端脚本(我使用python3.8.2)

import socket

#defin socket object
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((socket.gethostname(), 0))
s.listen(5)
while True:
    clientsocket, address = s.accept()
    print(f"connection from client has been established")
    clientsocket.send(bytes("welcome to the server!", "utf-8"))

我的服务器端脚本运行良好,但是当我运行客户端脚本时

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((socket.gethostname(127.0.0.1), 0))
msg = s.recv(1024)
print(msg.decode("utf-8")) 

我得到以下信息:

File "client.py", line 3
    s.connect((socket.gethostname(127.0.0.1), 0))
                                       ^
SyntaxError: invalid syntax

我尝试将 IP 更改为我的计算机主机名并给出以下信息:

raceback (most recent call last):
  File "client.py", line 3, in <module>
    s.connect(socket.gethostname((LAPTOP-XXXXXXX), 0))
NameError: name 'LAPTOP' is not defined

【问题讨论】:

    标签: python python-3.x sockets networking


    【解决方案1】:

    有多个问题:

    • 在指定 IP 地址和主机名时,它们必须格式化为字符串(例如 "127.0.0.1""LAPTOP-XXXXXXX")。不带引号指定它​​们会导致 Python 尝试将它们解释为其他标记,例如变量名、保留关键字、数字等,这会导致错误,例如 SyntaxError 和 NameError。
    • socket.gethostname() 不接受参数
    • socket.bind() 调用中指定端口 0 会导致分配一个随机的高编号端口,因此您需要对使用的端口进行硬编码或在客户端中动态指定正确的端口(例如,在执行程序)
    • 在服务器代码中,socket.gethostname() 可能最终不会使用环回地址。这里的一种选择是使用an empty string, which results in accepting connections on any IPv4 address

    这是一个有效的实现:

    server.py

    import socket
    
    HOST = ''
    PORT = 45555
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((HOST, PORT))
    host_addr = s.getsockname()
    print("listening on {}:{}".format(host_addr[0], host_addr[1]))
    s.listen(5)
    while True:
        client_socket, client_addr = s.accept()
        print("connection from {}:{} established".format(client_addr[0], client_addr[1]))
        client_socket.send(bytes("welcome to the server!", "utf-8"))
    

    client.py

    import socket
    
    HOST = '127.0.0.1'
    PORT = 45555
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((HOST, PORT))
    msg = s.recv(1024)
    print(msg.decode("utf-8"))
    

    来自服务器的输出:

    $ python3 server.py
    listening on 0.0.0.0:45555
    connection from 127.0.0.1:51188 established
    connection from 127.0.0.1:51244 established
    

    来自客户端的输出:

    $ python3 client.py
    welcome to the server!
    $ python3 client.py
    welcome to the server!
    

    【讨论】:

    • 感谢您的帮助!阅读您的代码后,我对它有了更好的理解,但我对以下几行感到困惑:print({}:{}".format(host_addr[0], host_addr[1]))。我想也许 {}:{} 正在以某种方式指定 ip 和端口,但我不确定 host_addr[0] 和 host_addr[1] 在代码中也指的是什么
    • socket.getsockname() 返回a (host, port) tuple in the AF_INET (IPv4) context。所以host_addr[0]host_addr[1] 指的是该元组的第一个和第二个元素。关于字符串中{} 的实例,这些是由传递给str.format() method 的参数替换的占位符。
    【解决方案2】:

    将 127.0.0.1 作为字符串放入 gethostname

    【讨论】:

      【解决方案3】:

      /etc/hosts 文件内容中,您将拥有一个IP 地址映射,其中“127.0.1.1”到您的主机名。这将导致名称解析得到 127.0.1.1。只需评论这一行。因此,局域网中的每个人都可以在连接到您的 ip (192.168.1.*) 时接收数据。使用threading管理多个客户端。

      这是服务器和客户端代码: 服务器代码:

      import socket
      import os
      from threading import Thread
      import threading
      import time
      import datetime
      
      def listener(client, address):
          print ("Accepted connection from: ", address)
          with clients_lock:
              clients.add(client)
          try:    
              while True: 
                  client.send(a)
                  time.sleep(2)   
      
          finally:
              with clients_lock:
                  clients.remove(client)
                  client.close()
      
      clients = set()
      clients_lock = threading.Lock()
      
      host = socket.getfqdn()  # it gets ip of lan
      port = 10016
      
      s = socket.socket()
      s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
      s.bind((host,port))
      s.listen(3)
      th = []
      print ("Server is listening for connections...")
      while True:
          client, address = s.accept()
          timestamp = datetime.datetime.now().strftime("%b %d %Y,%a, %I:%M:%S %p")
          a = ("Hi Steven!!!" + timestamp).encode()
          th.append(Thread(target=listener, args = (client,address)).start())
      s.close()
      

      客户代码:

      import socket
      import os
      import time
      
      s = socket.socket()  
      host = '192.168.1.43' #my server ip 
      port = 10016
      print(host)
      print(port)
      
      s.connect((host, port))
      while True:
          print((s.recv(1024)).decode())
      s.close() 
      

      输出:

      (base) paulsteven@smackcoders:~$ python server.py 
      Server is listening for connections...
      Accepted connection from:  ('192.168.1.43', 38716)
      
      
      (base) paulsteven@smackcoders:~$ python client.py 
      192.168.1.43
      10016
      Hi Steven!!!Feb 19 2020,Wed, 11:13:17 AM
      Hi Steven!!!Feb 19 2020,Wed, 11:13:17 AM
      Hi Steven!!!Feb 19 2020,Wed, 11:13:17 AM
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-04-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多