c#与Python的通信-由于目标机器主动拒绝,无法建立连接



我试图通过TCP/IP连接建立通信,并且在将c#客户端连接到Python服务器时遇到问题。它抛出一个SocketException:

System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused it

我很确定它发生在它试图连接到Python服务器的行:sender.Connect(remoteEP);

What I've try

  • 在我使用IPv4协议和pythonsocket.AF_INET之前,但我发现似乎我在c#中对IP地址的解析使其成为IPv6地址,所以这就是我现在使用的,但这并没有解决问题。
  • 我还尝试使用IPAddress.Parse(ip)而不是首先使用Dns.GetHostEntry(ip)获得主机,但似乎没有做任何事情。

的代码c#代码:
using UnityEngine;
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.Text;

public class PyCommunicator : MonoBehaviour {
private string ip = "::1"; // Localhost
private int port = 14654;
public string dataStringToSend
{
get { return dataStringToSend; }
set { dataStringToSend = value; }
}
private void Start()
{
StartCoroutine(RequestServerCoroutine());
}
IEnumerator RequestServerCoroutine()
{
while (true)
{
RequestServer();
yield return new WaitForSecondsRealtime(10);
}
}
public void RequestServer()
{
byte[] bytes = new byte[1024]; // 1 KiloByte
try
{
// Connect to a Remote server,
// and get host IP Address that is used to establish a connection.
// In this case, we get one IP address of localhost that is IPv6 : ::1 
// If a host has multiple addresses, you will get a list of addresses  
IPHostEntry host = Dns.GetHostEntry(ip);
IPAddress ipAddress = host.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
// Create a TCP/IP  socket.    
Socket sender = new Socket(AddressFamily.InterNetworkV6,
SocketType.Stream, ProtocolType.Tcp);
// Connect the socket to the remote endpoint. Catch any errors.    
try
{
// Connect to Remote EndPoint  
sender.Connect(remoteEP);
Debug.Log("Successfully established a connection between Unity and Python.");
// Encode the data string into a byte array.
dataStringToSend = "Test from C#";
if (dataStringToSend != "")
{
byte[] msg = Encoding.ASCII.GetBytes(dataStringToSend);
// Send the data through the socket.
int bytesSent = sender.Send(msg);
// Reset.
dataStringToSend = "";
}
// Receive the response from the remote device.    
int bytesRec = sender.Receive(bytes);
Debug.LogFormat("Echoed test = {0}",
Encoding.ASCII.GetString(bytes, 0, bytesRec));
// Release the socket.    
sender.Shutdown(SocketShutdown.Both);
sender.Close();
}
catch (ArgumentNullException ane)
{
Debug.LogFormat("ArgumentNullException: {0}", ane.ToString());
}
catch (SocketException se)
{
Debug.LogFormat("SocketException: {0}", se.ToString());
}
catch (Exception e)
{
Debug.LogFormat("Unexpected exception: {0}", e.ToString());
}
}
catch (Exception e)
{
Debug.LogFormat("Exception from setup: {0}", e.ToString());
}
}
}

c#代码取自客户端部分的这个链接,并根据我自己的使用进行了修改。

Python代码:

import socket
from time import sleep

class Communicator():
def __init__(self, ip, port):
self.ip = ip
self.port = port
self.data_to_send = None
self.socket = None
self.socket_conn = None
self.socket_addr = None
# Start listening right away.
self.start()

def start(self):
"""Start listening and accept connection."""
self.socket = socket.socket(socket.AF_INET6,  socket.SOCK_STREAM)
self.socket.bind((self.ip, self.port))
# Begin listening for 1 connection.
self.socket.listen(1)
print("Socket is listening on ip (" + str(self.ip) + ") and port " + str(self.port))
self.socket_conn, self.socket_addr = self.socket.accept()
print("Connection between Unity and Python established. Unity-C# is at: " + str(self.socket_addr))

sleep(5) # TESTING PURPOSES
# Receive.
result = ""
chunk_counter = 0
while True:
# Allow the server to read up to 1024 bytes.
data = self.conn.recv(1024)
chunk_counter += 1
# To minimize lag, read guess in chunks.
if chunk_counter < 5:
result += data.decode()

# If reading the guess is done,
# break out of loop.
if not data:
break

# Send.
self.socket.send("Test from python".encode())
# Close
self.socket.close()

def send_data(self):
"""Send data"""
pass

def receive_data(self):
"""Receive data"""
pass

Communicator('::1', 14654)

似乎我没有搜索足够的StackOverflow论坛。我在这个StackOverflow答案中给出的代码和答案中找到了一个解决方案。

我不需要使用实际的localhost环回地址,而是需要通过c#的DNS函数获得HOSTNAME地址:

Dns.GetHostName()

我还在Python中使用了socket.gethostname(),以便它们在连接时具有相同的地址。

我也改变了整个事情使用IPv4地址,并在链接问题的答案中发现host.AddressList中的第一个元素包含IPv6地址,而第二个和最后一个元素包含IPv4地址,这是缺失的部分。

更新代码c#代码:

using UnityEngine;
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.Text;

public class PyCommunicator : MonoBehaviour {
private int port = 14654;
public string dataStringToSend
{                                                                               
get { return dataStringToSend; }
set { dataStringToSend = value; }
}
private void Start()
{
StartCoroutine(RequestServerCoroutine());
}
IEnumerator RequestServerCoroutine()
{
while (true)
{
RequestServer();
yield return new WaitForSecondsRealtime(10);
}
}
public void RequestServer()
{
byte[] bytes = new byte[1024]; // 1 KiloByte
try
{
// Connect to a Remote server,
// and get host IP Address that is used to establish a connection.
// In this case, we get one IP address of localhost that is IP : 127.0.0.1
// If a host has multiple addresses, you will get a list of addresses  
IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = host.AddressList[1];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
// Create a TCP/IP  socket.    
Socket sender = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Connect the socket to the remote endpoint. Catch any errors.    
try
{
// Connect to Remote EndPoint  
sender.Connect(remoteEP);
Debug.Log("Successfully established a connection between Unity and Python.");
// Encode the data string into a byte array.
dataStringToSend = "Test from C#";
if (dataStringToSend != "")
{
byte[] msg = Encoding.ASCII.GetBytes(dataStringToSend);
// Send the data through the socket.
int bytesSent = sender.Send(msg);
// Reset.
dataStringToSend = "";
}
// Receive the response from the remote device.    
int bytesRec = sender.Receive(bytes);
Debug.LogFormat("Echoed test = {0}",
Encoding.ASCII.GetString(bytes, 0, bytesRec));
// Release the socket.    
sender.Shutdown(SocketShutdown.Both);
sender.Close();
}
catch (ArgumentNullException ane)
{
Debug.LogFormat("ArgumentNullException: {0}", ane.ToString());
}
catch (SocketException se)
{
Debug.LogFormat("SocketException: {0}", se.ToString());
}
catch (Exception e)
{
Debug.LogFormat("Unexpected exception: {0}", e.ToString());
}
}
catch (Exception e)
{
Debug.LogFormat("Exception from setup: {0}", e.ToString());
}
}
}

Python代码:

import socket
from time import sleep

class Communicator():
def __init__(self, ip, port):
self.ip = ip
self.port = port
self.data_to_send = None
self.socket = None
self.socket_conn = None
self.socket_addr = None
# Start listening right away.
self.start()

def start(self):
"""Start listening and accept connection."""
self.socket = socket.socket(socket.AF_INET,  socket.SOCK_STREAM)
self.socket.bind((self.ip, self.port))
# Begin listening for 1 connection.
self.socket.listen(1)
print("Socket is listening on ip (" + str(self.ip) + ") and port " + str(self.port))
self.socket_conn, self.socket_addr = self.socket.accept()
print("Connection between Unity and Python established. Unity-C# is at: " + str(self.socket_addr))

sleep(5) # TESTING PURPOSES
# Receive.
result = ""
chunk_counter = 0
while True:
# Allow the server to read up to 1024 bytes.
data = self.conn.recv(1024)
chunk_counter += 1
# To minimize lag, read guess in chunks.
if chunk_counter < 5:
result += data.decode()

# If reading the guess is done,
# break out of loop.
if not data:
break

# Send.
self.socket.send("Test from python".encode())
# Close
self.socket.close()

def send_data(self):
"""Send data"""
pass

def receive_data(self):
"""Receive data"""
pass

Communicator(socket.gethostname(), 14654)

相关内容

最新更新