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