【发布时间】:2019-03-30 22:48:35
【问题描述】:
我正在为我的关卡项目使用 C# 和 unity 编写消息传递应用程序,它使用 tcp 客户端-服务器模型。我已经创建了一个可以接收消息的套接字列表,但是我必须指定要从中接收消息的套接字,这对于我只有 1 个客户端的测试很好,但是我需要能够处理更多的连接和循环通过每个套接字尝试并从中接收消息似乎非常低效且缓慢。
我的问题是:不使用上述方法,如何接收来自多个客户端的消息?
我将发布特定部分,然后是整个代码,以便您了解我在做什么。
这是处理从套接字接收数据的线程
public static void Thread1()
{
for (int i = 0; i <= 2; i++)
{
byte[] b = new byte[155];
///////// I need to specify the socket to receive from////////
int k = counter.numbers1[counter.i2].Receive(b);
//////////////////////////////////////////////////////////////
string k1 = "";
for (int i3 = 0; i3 < k; i3++)
k1 = k1 + Convert.ToChar(b[i3]);
Console.WriteLine(k1);
string sender_endpoint = k1.Substring(0, 21); ;
string receiver_endpoint = k1.Substring(22, 21);
string message = k1.Substring(44, 100);
string msgtype = k1.Substring(145, 1);
Console.WriteLine(k1.Length);
Console.WriteLine(sender_endpoint);
Console.WriteLine(receiver_endpoint);
Console.WriteLine(message);
Console.WriteLine(msgtype);
if (msgtype == "0") //message
{
Console.WriteLine("000");
}
else if (msgtype == "1") //command
{
Console.WriteLine("111");
}
}
}
完整的服务器代码是:
namespace server
{
static class counter
{
public static int i2 = 0;//main listener
public static int i4 = 0;//port number
public static List<TcpListener> numbers = new List<TcpListener>();//listeners
public static List<Socket> numbers1 = new List<Socket>();//sockets
}
class server_code
{
public static void Main()
{
string xyz123 = "x";
Thread thread3 = new Thread(new ThreadStart(Thread3));
Thread test_thread = new Thread(() => Test_Thread (xyz123));
thread3.Start();
}
public static void Thread1()
{
//message reactions
for (int i = 0; i <= 2; i++)
{
byte[] b = new byte[155];
int k = counter.numbers1[counter.i2].Receive(b);
string k1 = "";
for (int i3 = 0; i3 < k; i3++)
k1 = k1 + Convert.ToChar(b[i3]);
Console.WriteLine(k1);
string sender_endpoint = k1.Substring(0, 21); ;
string receiver_endpoint = k1.Substring(22, 21);
string message = k1.Substring(44, 100);
string msgtype = k1.Substring(145, 1);
Console.WriteLine(k1.Length);
Console.WriteLine(sender_endpoint);
Console.WriteLine(receiver_endpoint);
Console.WriteLine(message);
Console.WriteLine(msgtype);
if (msgtype == "0") //message
{
Console.WriteLine("000");
}
else if (msgtype == "1") //command
{
Console.WriteLine("111");
}
}
}
public static void Thread2()
{
//client message receiver
var host = Dns.GetHostEntry(Dns.GetHostName());
foreach (var ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
IPAddress ipAd = IPAddress.Parse(ip.ToString());
counter.numbers.Add(null);
counter.numbers1.Add(null);
Console.WriteLine("");
Socket xyz1 = counter.numbers[counter.i2].AcceptSocket();
counter.numbers1[counter.i2] = xyz1;
ASCIIEncoding asen = new ASCIIEncoding();
counter.numbers1[counter.i2].Send(asen.GetBytes(counter.numbers1[counter.i2].RemoteEndPoint.ToString()));
Console.WriteLine("Connection accepted from " + counter.numbers1[counter.i2].RemoteEndPoint);
Console.WriteLine("connecting to " + counter.numbers[counter.i2].LocalEndpoint);
//System.Threading.Thread.Sleep(3000);
Thread thread1 = new Thread(new ThreadStart(Thread1));
thread1.Start();
}
}
}
public static void Thread3()
{
//new clients acception
var host = Dns.GetHostEntry(Dns.GetHostName());
foreach (var ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
for (int i = 0; i <= 10; i++)
{
Console.WriteLine(ip.ToString());
IPAddress ipAd = IPAddress.Parse(ip.ToString());
TcpListener myList = new TcpListener(ipAd, 8080);
myList.Start();
Console.WriteLine("The local endpoint is :" + myList.LocalEndpoint);
Socket s = myList.AcceptSocket();//////////////////////////////////////////////
Console.WriteLine("Connection accepted from " + s.RemoteEndPoint);
Console.WriteLine("connecting to " + myList.LocalEndpoint);
ASCIIEncoding asen = new ASCIIEncoding();
counter.i2 = counter.i2 + i;
int portno = 8000;
s.Send(asen.GetBytes(portno.ToString()));
Console.WriteLine();
myList.Stop();
s.Close();
Thread thread2 = new Thread(new ThreadStart(Thread2));
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
counter.numbers.Add(null);
TcpListener xyz = new TcpListener(ipAd, portno);
counter.numbers[counter.i2] = xyz;
//Console.WriteLine(counter.i4);//current portno
counter.numbers[counter.i2].Start();
Console.WriteLine("The local End point is :" + counter.numbers[counter.i2].LocalEndpoint);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
thread2.Start();
}
}
}
}
}
完整的客户端代码是:
public class cc : MonoBehaviour
{
public InputField NameField;
private string x;
private string y = "";
//private int z = 0;
static class ipadressnumber{
public static string ipadressno = "192.168.1.250";
}
public void Start(){
TcpClient tcpclnt = new TcpClient();
tcpclnt.Connect(ipadressnumber.ipadressno,8080);
Stream stm = tcpclnt.GetStream();
byte[] bb=new byte[100];
int k=stm.Read(bb,0,100);
for (int i=0;i<k;i++){
y = y + Convert.ToChar(bb[i]);
}
//Debug.Log(y);
tcpclnt.Close();
}
public void OnSubmit()
{
x = NameField.text;
//Debug.Log(x);
try
{
System.Net.IPAddress ipad = IPAddress.Parse(ipadressnumber.ipadressno);
IPEndPoint ipLocalEndPoint = new IPEndPoint(ipad,8888);
//TcpClient clientSocket = new TcpClient(ipLocalEndPoint);
TcpClient tcpclnt1 = new TcpClient();
//Debug.Log(y);
tcpclnt1.Connect(ipadressnumber.ipadressno,int.Parse(y));
Stream stm = tcpclnt1.GetStream();
byte[] bb=new byte[100];
int k=stm.Read(bb,0,100);
string lclep = "";
for (int i=0;i<k;i++)
{
lclep = lclep + Convert.ToChar(bb[i]);
}
String str=x;
////////////format of message:(sender endpoint, recipient endpoint, message, message type, check sum/digit)
string message = "";
int strlen = 21;
int msglen = 100;
string msgtype = "0";// 0 = message, 1 = command
lclep = Convert.ToString(lclep);
Debug.Log (lclep);
while (strlen > lclep.Length)
{
Debug.Log('1');
lclep = lclep + "#";
}
string rmtep = "000.00.00.000:8000";
while (strlen > rmtep.Length)
{
Debug.Log ('2');
rmtep = rmtep + "#";
}
while (msglen > x.Length)
{
Debug.Log ('3');
x = x + "#";
}
message = message + lclep + ':' + rmtep + ':' + x + ':' + msgtype + ':';
Debug.Log(message);
ASCIIEncoding asen= new ASCIIEncoding();
byte[] ba = new byte[155];
ba=asen.GetBytes(message);
stm.Write(ba,0,ba.Length);
tcpclnt1.Close();
}
catch (Exception e) {
Console.WriteLine("Error..... " + e.StackTrace);
}
}
}
输出是这样的:
192.168.1.250
The local End point is :192.168.1.250:8080
Connection accepted from 192.168.1.250:54024
connecting to 192.168.1.250:8080
The local End point is :192.168.1.250:8000
192.168.1.250
The local End point is :192.168.1.250:8080
Connection accepted from 192.168.1.250:54055
connecting to 192.168.1.250:8000
192.168.1.250:54055##:000.00.00.000:8000###:message test 1 for stackoverflow####################################################################:0:
147
192.168.1.250:54055##
000.00.00.000:8000###
message test 1 for stackoverflow####################################################################
0
000
如您所见,我没有收到任何错误,所以我只需要一种从多个客户端接收消息的方法。
【问题讨论】:
-
只是一个未来的说明,我们不需要看到你使用命名空间声明,
-
好的,谢谢,不知道人们需要什么来解决问题,不想冒险。将来不会包含它。
-
“循环遍历每个套接字以尝试从中接收消息”——这称为“轮询”,您永远不应该这样做。正如你所说,它是低效的。也就是说,如果你真的做了一些重要的研究,你会发现各种技术可以从套接字读取数据,特别是当它们有数据要读取时,大多数“异步”类型,尽管一个选项实际上是专用一个线程每个插座...
-
...(仅当您处理非常少量的套接字时才可接受...最多几十个)。为了让您了解该主题,您应该只查找参考资料,这对于 Stack Overflow 来说太宽泛了。
-
错字提醒:它是 receive - 不是“receive” ....
标签: c# tcp tcplistener tcpsocket