C#有没有办法做socket转接? 30

服务端S,两个客户端A、B,客户端都是在局域网内没有公网IP,如果AB要通信,一般是通过S直接中转信息,这样势必浪费很多的服务端的资源,例如最重要的带宽,有没有办法让服务... 服务端S,两个客户端A、B,客户端都是在局域网内没有公网IP,
如果AB要通信,一般是通过S直接中转信息,
这样势必浪费很多的服务端的资源,例如最重要的带宽,
有没有办法让服务端跟AB建立的两个通道直接对接,服务端只负责前期的对接工作,后期的通信A和B直接发送和接收呢?
很多P2P的例子都是扯淡完全没这个功能,
展开
 我来答
samismiling
2020-02-21 · 知道合伙人软件行家
samismiling
知道合伙人软件行家
采纳数:1340 获赞数:5604

向TA提问 私信TA
展开全部
可以,内网之间实现TCP通讯需要用到内网穿透技术。
以下是示例代码。
服务端代码:

static void Main(string[] args)
{
int port = 555;
IPEndPoint ipe = new IPEndPoint(IPAddress.Any, port);
Socket sSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sSocket.Bind(ipe);
sSocket.Listen(100);
Console.WriteLine("监听已经打开,请等待");

while (true)
{
Socket serverSocket1 = sSocket.Accept();
Console.WriteLine("连接已经建立");
string recStr = "";
byte[] recByte = new byte[4096];
int bytes = serverSocket1.Receive(recByte);
IPEndPoint ep1 = (IPEndPoint)serverSocket1.RemoteEndPoint;
Console.WriteLine(" from {0}", ep1.ToString());
recStr = Encoding.ASCII.GetString(recByte, 0, bytes);
Console.WriteLine("客户端1:{0}", recStr);

Socket serverSocket2 = sSocket.Accept();
bytes = serverSocket2.Receive(recByte);
IPEndPoint ep2 = (IPEndPoint)serverSocket2.RemoteEndPoint;
Console.WriteLine(" from {0}", ep2.ToString());
recStr = Encoding.ASCII.GetString(recByte, 0, bytes);
Console.WriteLine("客户端2:{0}", recStr);

byte[] sendByte =Encoding.ASCII.GetBytes(ep1.ToString() + ":" + ep2.ToString());
serverSocket1.Send(sendByte, sendByte.Length, 0);

sendByte = Encoding.ASCII.GetBytes(ep2.ToString() + ":" + ep1.ToString());
serverSocket2.Send(sendByte, sendByte.Length, 0);

serverSocket1.Close();
serverSocket2.Close();
}

}
功能:两边客户端连接服务器后将映射的外网IP和端口号传给双方。

客户端代码
static void Main(string[] args)
{
string host = "115.21.X.X";//服务端IP地址
int port = 555;
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//设置端口可复用
clientSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
//连接服务端
clientSocket.Connect(host, port);
Console.WriteLine("Connect:" + host + " " + port);

string data = "hello,Server!";
clientSocket.Send(Encoding.ASCII.GetBytes(data));
Console.WriteLine("Send:" + data);
byte[] recBytes = new byte[100];
//获取到双方的ip及端口号
int bytes = clientSocket.Receive(recBytes, recBytes.Length, 0);
string result = Encoding.ASCII.GetString(recBytes, 0, bytes);
Console.WriteLine("Recv:" +result);
clientSocket.Close();

string[] ips = result.Split(':');
int myPort = Convert.ToInt32(ips[1]);
string otherIp = ips[2];
int otherPort = Convert.ToInt32(ips[3]);

Socket mySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
mySocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
//绑定到之前连通过的端口号
IPEndPoint ipe = new IPEndPoint(IPAddress.Any, Convert.ToInt32(myPort));
mySocket.Bind(ipe);
//尝试5次连接
for (int j = 0; j < 5; j++)
{
try
{
mySocket.Connect(otherIp, otherPort);
Console.WriteLine("Connect:成功{0},{1}", otherIp,otherPort);
break;
}
catch (Exception)
{
Console.WriteLine("Connect:失败");
// otherPort++;//如果是对称NAT,则有可能客户端的端口号已经改变,正常有规律的应该是顺序加1,可以尝试+1再试(我使用手机热点连接的时候端口号就变成+1的了)除非是碰到随机端口,那就不行了。
}

}
while (true)
{
mySocket.Send(Encoding.ASCII.GetBytes("hello,the other client!"));

byte[] recv = new byte[4096];
int len = mySocket.Receive(recv, recv.Length, 0);
result = Encoding.ASCII.GetString(recv, 0, len);
Console.WriteLine("recv :" + result);

Thread.Sleep(1000);
}
}
另一边客户端也一样。连接服务器后,可以绑定之前的端口号复用,但如果碰到一端是对称NAT时每次使用端口号会不一样时,这样就得通过预测下次可能使用的端口号来连通。如:使用手机热点网络连接服务器时,获取到它使用的端口号是56324,等到下一次客户端互相连接使用56325才连上。
百度网友eb6ab18
2020-02-17 · TA获得超过585个赞
知道小有建树答主
回答量:1068
采纳率:83%
帮助的人:253万
展开全部
没做过这样的工作,不过如果是我来做的话,我可能会采用这样的方法:
A登录S,B也登录S,A发起连接B的请求(反之亦然),S把A和B的IP分别告诉对方,然后A和B另外单独建立连接,that'all
本回答被网友采纳
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
阳光的雷咩咩
2020-02-19 · TA获得超过1.4万个赞
知道大有可为答主
回答量:2.3万
采纳率:66%
帮助的人:7786万
展开全部
这有点类似vpn的场景,在S上搭建个vpn服务,a,b都连上这vpn,就可以像局域网一样通信了
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
神帝执
2020-04-16 · 娱乐而已,切勿依赖啊
神帝执
采纳数:20 获赞数:14

向TA提问 私信TA
展开全部
直接让ab互为服务端和客户端不就可以了吗
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
活宝运气
2020-02-24 · 超过71用户采纳过TA的回答
知道小有建树答主
回答量:149
采纳率:89%
帮助的人:21.6万
展开全部
例如qq的通信就是 你所说的场景 p2p通信。
挨着来分析你的问题,
1.A.B为什么不能直接通信 原因:A.B不在同一局域网内部
2.AS BS 为什么能直接通信 原因 S是公网ip
3.AS BS 直接通信 S端收到的请求 一定是由路由器 转换过后的映射 ip和端口
4.如果把S端收到的AB的路由器映射ip端口 交换给对应的AB 也就是说 吧S收到A的路由器外网ip加端口 返回给B B直接用这个端口加ip连接A 可行吗 不可行 原因 路由器机制
5.既然路由器有防护机制 可以破解吗 答案是肯定可以,首先学过网络技术的人都知道,路由器有个机制“一问一答” 数据想要发过来必须 内网中有个 请求请求过这个 端口。
6.那就继续第4步 A->B B将收不到数据 但是在 A的路由器上会有个向B的请求 B->A 这个时候数据就会成功发送到A上 这个过程被称为 路由器防火墙“打洞” 一旦打通以后AB直接必须 45秒以内 发送一次心跳包 路由器的端口映射一般是45秒钟 无数据发送 映射会被释放
7.这都是建立在 A->S A->B 时 路由器给你的映射 都是相同的,这里就涉及到路由器分类,根据安全级别分成 4大类 可以去网上查询资料 这里就不累述,最后一种高级别的路由器 会出现 每次请求不同的地址路由器 就会帮你映射不同的端口 之前的打洞流程就走不通的,目前也没有解决办法,现在大家的做法都是 如果能打洞就p2p通信 如果无法打洞 就通知S端做 数据中转。
特别提示 以上必须是 udp 我看到还有回答是 用tcp的 这是真的乱说
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
收起 3条折叠回答
收起 更多回答(4)
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式