socket编程,多端口
大家好,我现在有个项目,是socket通讯的。客户端已做好,是别人做的。每个客户端用到一个独立的端口,最多是999个,请问我上位机得针对这999个独立端口开启999个服务进行侦听吗?那是不是会创建太多的线程? --------------------编程问答-------------------- 当然不用,因为服务器的端口就一个,就监听这一个端口就行了,就用一个或几个线程去监听端口的消息然后把收到的连接存放到一个表中,比如hashtable
根据端口收到的消息再取到对应的连接进行处理 --------------------编程问答--------------------
纠正下楼主的概念,“上位机”个人认为应该是相对于嵌入式终端的“下位机”而言的吧。这里应该说成“客户端”和“服务器”吧?
你所说的每个客户端用到一个独立端口,是指每个客户端程序都访问你服务器的一个特定端口呢?还是指的每个客户端都用自己的某一个端口访问你服务器上的相同的一个端口?比如每个客户端都访问服务器的8888端口?
如果是前一种情况,你就得为每一个客户端要访问的每个端口都建立一个线程,然后侦听客户端的连接。
如果是后一种情况(我估计99%是这种情况),你只需启动一个线程,然后侦听客户端需要连接到的你的服务器的这个端口,每当收到一个连接的时候,就启动一个线程,把这个连接的客户端Socket(Accept会返回一个客户端socket对象)作为线程目标函数的参数传到线程的目标函数里去,然后再在这个函数里处理跟客户端之间的收发数据即可。 --------------------编程问答-------------------- 对,我这个的下位机就是嵌入式式终端。每个客户端访问我的服务器的一个特定端口,比如说有999台客户端,就是访问我的端口(10001---10999)。这样我要是建立这么多线程会不会造成服务器开线程太多,而死机什么的? --------------------编程问答-------------------- listen那么多不是cpu线程,不会死机的。不行你测试一下看看。 --------------------编程问答-------------------- beginaccept和acceptasync都不是使用处理器线程的,除非你硬性开1000个处理器线程,那就不行了。 --------------------编程问答--------------------
哦这样子啊?
那你为什么不让着999台终端都访问你的服务器上的同一个端口呢? --------------------编程问答-------------------- 我觉得还是在网关上做个端口映射吧。
我所知道的类似的系统都是采用2楼所说的第二种情况。
不知道是否我孤陋寡闻了。。。 --------------------编程问答-------------------- 如果你实在没办法让他们都来连接你的服务器上的同一端口的话,那么只有祈祷了……
请参考如下文章:
讨论:一个进程(Process)最多可以生成多少个线程(Thread) --------------------编程问答-------------------- 客户端的内容是早就做好了,我们现在是配合他们升级服务器端软件,原来用的vb做的c/s的。现在我想改为b/s的,但通讯这块还得借就以前的模式,他们当时客户端上传时没有客户端的标志,这样若服务器使用同一端口跟他们所有的连接时,给客户端发送信息就不知该如何发,才能发给指定的那个客户端了。 --------------------编程问答-------------------- 我的客户端中不是固定ip,用的手机卡,走的gprs,ip是动态的,就是停一次电后ip会变的。 --------------------编程问答--------------------
那采用连接1000个不同的服务器端口又怎么解决这个问题的? --------------------编程问答-------------------- 实时性不是很高的话,可以建一个后台线程来采用轮询所有端口。
实时性高的话,那就必须用线程来了,说实话1000个线程的程序没写过,需要点啥还真不清楚。
关注大婶们的讨论 --------------------编程问答-------------------- 其实若不考虑交互信息(就是除接收信息外,服务器还可任意时间给指定的客户端发送命令立即读取信息),只接收信息的话现在也可做成访问同一端口的。原来的因为在服务器都绑定了固定端口,所以要向哪个终端发送信息时,只要直接往对应端口发送信息就行了。原来的服务器软件也不是我做的。 --------------------编程问答-------------------- 实时性不是很高的话,可以建一个后台线程来采用轮询所有端口。这样也不错。我们一般6分钟采一次数据然后上传服务器。 --------------------编程问答-------------------- 那你就放心监听1000个端口吧,不会产生1000个cpu线程,不用担心。 --------------------编程问答-------------------- 好的,多谢各位的参与,我再多试试。 --------------------编程问答-------------------- 为了让你更加放心,我测试了一下1000个socket监听1000个端口并beginaccept,结果cpu占用0,内存4兆,给你看一下数据,嘿嘿。原因我在前面已经解释过,这些是io线程,不是处理器线程。 --------------------编程问答--------------------
太感谢lizhibin11了,这下我就放心了,非常感谢! --------------------编程问答-------------------- 提醒一下,一定不要用thread,而是用socket异步编程,例如beginaccept、beginreceive、beginsend或者socketasynceventargs,这些都是完成端口的,创建的是io线程。 --------------------编程问答-------------------- 哦,我正在考虑用thread怎么实现开辟999个呢,你说的异步这个我还得看一下,以前做时用的是thread,所以也考虑用这个呢。 --------------------编程问答-------------------- lizhibin11你好,你是怎么创建的那个测试1000个端口接收的程序的,能发给我看看吗?ysfx@yahoo.com.cn --------------------编程问答--------------------
using System;
using System.Net;
using System.Net.Sockets;
namespace ConsoleApplication7
{
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 1000; i++)
{
Socket sk = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sk.Bind(new IPEndPoint(IPAddress.Parse( "192.168.1.101"), 10000 + i));
sk.Listen(1);
sk.BeginAccept(acceptCallBack, sk);
}
Console.WriteLine("ok");
Console.ReadLine();
}
static void acceptCallBack(IAsyncResult result)
{
Socket sk = (Socket)result.AsyncState;
sk = sk.EndAccept(result);
byte[] b = new byte[1024];
sk.BeginReceive(b, 0, b.Length, SocketFlags.None, ReceiveCallBack, sk);
}
static void ReceiveCallBack(IAsyncResult result)
{
Socket sk = (Socket)result.AsyncState;
int len = sk.EndReceive(result);
//........................
}
}
}
测试程序,只是雏形。正式应用需要有全局集合保存socket以便调用它发送东西。 --------------------编程问答-------------------- 如果你跟下位机的通信协议里包含了手机号的话,最好用手机号做区分,这样也可以避免占用1000个端口的问题。
另外提醒你一下。如果服务器不需要用DNS服务的话,把服务器的DNS服务停掉,不然的话,容易造成端口被占用完的问题,导致无法接收数据。我曾经碰到过。
--------------------编程问答-------------------- 这个是轮询啊,而且sk.BeginAccept(acceptCallBack, sk);
需要放到线程的while死循环里用for语句执行1000个socket的轮询,异步接收数据。
轮询到了还要用个queue去保存当前通讯的ip地址,用来处理发送逻辑。 --------------------编程问答-------------------- 轮询也是个不错的做法,单线程就可以。
不过1000个客户端对于轮询来说有点多了,还是完成端口稍微好一些。 --------------------编程问答-------------------- 如果是用.net做,就用异步通讯轻松实现,如果是用vc做,就用完成端口也可以轻松实现,二者实质一样。 --------------------编程问答-------------------- 怎么需要那么多线程 谁还用同步???
去下个北风之神SOCKET 框架看下 就知道了 --------------------编程问答-------------------- 现在是通讯协议里没加手机号或别的用来区分终端的特征字,所以没法用同一端口号了。我先跟据大家的思路实现以下看看情况如何。
--------------------编程问答-------------------- 那服务器在同一个时间连接的客户机就应该有个上限的吧。 --------------------编程问答--------------------
如果只是使用一个端口 会丢包 吧 、、、 --------------------编程问答--------------------
还是服务器同一端口监听比较现实
应该有mac地址可作识别,如果是用udp通讯,每次通讯前,可以先广播一个命令(一般应该有这样的命令让下位机返回自己信息),让所有客户端给服务器返回信息(最好有mac这样的标识信息),这样你就能动态记录它们各自的标识信息+动态ip+端口号了
补充:.NET技术 , C#