RT
1.在服务器端,使用网络消息通知模式处理的情况下(wsaasyncselect),
每连接一个客户端,就会生成一个新的 socket来跟客户端进行通讯
而原来创建的socket 则可以继续监听客户端来的连接,
问题来了,在多个客户端连接的情况下,是不是每有一个客户端连接,都得定义一个对应的socket来与客户端进行通讯?
那几千上万个客户端连接时,怎么搞?
2.TCP连接的情况下进行nat穿透的问题(通过客户端的socket进行端口重用的方式实现,setsock()函数重定位端口和地址)。
如果两个客户端的NAT网络类型达不到要求(具体的忘了)时,是不是就不能实现P2P的功能?

解决方案 »

  1.   

    1, 多客户端连接的情况下,就是么个客户端一个socket。据说windows下目前效率最高的iocp模型,你可以google一下 IOCP 。
    2,tcp穿透很麻烦,udp的稍微容易些。另外跟peer端的网络类型有关,记忆力必须是锥型的才可以。
      

  2.   

    1。那不是要在服务器端为每个连接后的SOCKET都写一个网络消息事件?那不太现实吧。
    看来UDP和TCP都一样,不是任何情况下都能穿透的
      

  3.   

    iocp模型,倒用不着,使用消息和事件通知这两种模型,已经足够一般的应用程序使用了,只是我还不知道怎么处理服务器端跟每一个客户的通讯(多对一)
      

  4.   


    同一个消息事件同时为所有本访问端所连的socket服务,在事件的参数里传递了足够区分哪个socket的信息了
      

  5.   


    //与客户端连接后的SOCK所产生的网络事件
    procedure TForm1.WMCORRESPONDSOCK(var message: TMessage);
    var
      ret : integer;
      fbuf : array[0..255] of Char;
      FClientAdd: sockaddr_in;
    begin
      aSize := SizeOf(sockaddr_in);
      recvfrom(AcceptSock,fbuf,Length(fbuf) * SizeOf(Char),0,Add,aSize);
      case  WSAGetSelectEvent(message.LParam) of
        FD_READ :
        begin
            ret := recv(AcceptSock,fbuf,256,0);
            mmo1.Lines.Add('客户端来的消息 : ' + fbuf);
        end;
      end;
    end;
    //监视SOCK 所产生的网络消息事件
    procedure TForm1.WMSERVERSOCK(var message: TMessage);
      var  FdSet : TFDSet;
           TimeVal : TTimeVal;
           AddSize : integer;
           Add: TSockAddrIn;
    begin
      case  WSAGetSelectEvent(message.LParam) of
        FD_ACCEPT :
        begin
            AddSize := sizeof(Add);
           AcceptSock := accept(FSock,@Add,@AddSize); 
           if AcceptSock <> INVALID_SOCKET then
            WSAAsyncSelect(AcceptSock,Handle,WM_CORRESPONDSOCK,FD_READ or FD_WRITE  or FD_CLOSE);
        end;
      end;
    end;
    上面的代码,WMSERVERSOCK 即为服务器端的监听 socket ,响应其它客户端的连接,WMCORRESPONDSOCK消息处理过程中,可以获取是哪个客户端发过来的什么信息之类的东西,但是也不能排除两个或多个客户端同时向服务器端发送数据包,那这时服务器端在处理这个消息时会不会有什么冲突?在事件的参数里传递了足够区分哪个socket的信息了,那请问是什么信息呢?
    我也这样考虑过,但可能是我的程序处理有问题,当有第二个客户端连接时,服务器端会收到两次登录的消息,其实只有一个客户端发送了登录信息的数据
      

  6.   

    没有具体使用过
    猜测消息参数wParam 是socket 的句柄, lParam 是socket 事件
      

  7.   

    你的AcceptSock是什么?全局的?怎么都是使用它?
    哪个socket,应该是SOCKET sock = (SOCKET) wParam;好像这则说的不错:
    http://blog.chinaunix.net/u3/103892/showart_2050171.html
      

  8.   

    是全局的 AcceptSock 是 Server 端建立一个新的 socket 来对此连接做服务,而原先的 socket 则再回到监听等待的状态
      

  9.   


    我觉得问题应该就是在AcceptSock这里
      

  10.   

    谢谢各位,现在可以了,服务器端是要为第个连接的客户端都准备一个新的 socket ,在服务器端用一个结构数组保存了所有客户端的信息,包括连接后所用的 socket,在服务器端的消息事件处理中
    WSAGetSelectEvent(msg.wparam);就可以知道当前会话的是哪一个客户端...
    多连接的问题解决了
    不过还有一个问题,就是关于 通过setsockopt()这个函数,在客户端改变连接的IP和端口号,具体不知道怎么用
      

  11.   


    procedure WndProc(var AMsg: TMessage);
    var
      Error: word;
    begin
      with AMsg do
        case Msg of
          WM_ASYNCSELECT:    // 自定义消息头
            begin
              Error:= WSAGetSelectError(LParam);
              case WSAGetSelectEvent(LParam) of
                FD_READ  : TCPServerData(WParam);  // WParam 为 对应的 Socket
                FD_ACCEPT: OpenConnection(WParam, Error);
                FD_CLOSE : CloseConnection(WParam, Error);
              end;
            end;
        else
          Result:= DefWindowProc(FHandle, Msg, WParam, LParam);
        end;
    end;
    每个客户端进来的消息中,都包含了他的socket,服务器只需要针对它做应答就可以了
      

  12.   

    多连接问题已经解决,现在是关于客户端与客户端连接的问题了
    在客户端创建 socket 时加了这句,使地址端口重用
    var Flag : boolean;
        addr : tsockaddrIn;
      Flag := true;
      setsockopt(FSock,SOL_SOCKET,SO_REUSEADDR,@Flag,sizeof(Boolean));
      //并且返回成功
    但是我在重新在绑定 Fsock的端口时,返回错误
    如:获取到对方的地址后,将自己作为服务器端,重新绑定端口,并开启监听,等待对方连接
      addr.sin_family := PF_INET;
      addr.sin_port := htons(5236);
      addr.sin_addr.s_addr := INADDR_ANY;
       bing(FSock,addr,sizeof(addr)); //返回错误
    不知道哪位有没有处理过这种情况?
      

  13.   

    不知道LZ重新绑定的是哪个端口,好像客户端只需要绑定一次就可以了。
        服务器一般单独监听一个辅助打洞的端口 P,假如客户端A去请求打洞去连接B,则通过SERVER的端口P向B传输经过A转换后的公网IP地址和端口等信息, B收到后首先连接server端口P,随便发点消息后马上断开。这样做的目的是让S能知道B经过NAT-B转换后的公网IP和端口号。  
      B尝试与A的公网IP地址和端口进行connect,根据不同的路由器会有不同的结果,有些路由器在这个操作就能建立连接,大多数路由器对于不请自到的SYN请求包直接丢弃而导致connect失败,但A端的路由器会纪录此次连接的源地址和端口号,为接下来真正的连接做好了准备,这就是所谓的打洞,即B向A打了一个洞,下次A就能直接连接到B刚才使用的端口号了。
       客户端B打洞的同时在相同的端口上启动侦听。B在一切准备就绪以后通过与S的【主连接】回复消息“我已经准备好”,S在收到以后将B经过NAT-B转换后的公网IP和端口号告诉给A。
        A收到S回复的B的公网IP和端口号等信息以后,开始连接到B公网IP和端口号,由于B曾经尝试连接过A的公网IP地址和端口,NAT-A纪录了此次连接的信息,所以当A主动连接B时,NAT-B会认为是合法的SYN数据,并允许通过,从而直接的TCP连接建立起来了。  以上是网络上说的一种方法,确实可行,LZ可以参考下
      

  14.   

    是长连接,主要是想写成像UDP一样的点对点的传输,至于服务器端与客户端的通信倒不是很重要,目前就是
    网络消息的方式管理服务器端与客户端的连接
      

  15.   

     to: XD19861130
    我的想法是这样的,只不过不太明白何谓一个主连接,一个协助连接
    目前程序的结构就是这样:服务器端(S)建立一个 Socket 用来监听客户端来的连接
    每个客户端连接后,就记录客户端的信息,包括IP,端口,对应的通信socket 等等
    现在A,B都连接到了S端,那就S端就有三个socket,包括原先的监听socket,分别与客户端A,B连接后的 socketA,socketB ,我现在的做法就是,服务器端收到A要连接B的请求后,从S端返回B的IP和PORT给A,同时,给B发送A的IP和PORT信息。
    然后在客户端上用原来连接到 S端的socket 进行监听,并连接
    可结果总是不成功!!!!
      

  16.   

    先不管这样的方式对不对,就监听来说,只需要原来的端口号就可以了,而不是socket,所以会不成功。
    作为客户端,它原先connect服务器,其本地端口是系统分配的,必须先提取这个参数。以上是我的一些看法,不对之处还请指正。
      

  17.   

    S在p端口侦听,A以ip1、p1端口连上来,B以ip2、p2端口连上来
    A得到S告知的B的ip2,可以利用,但是p2是无法使用的,因为p2是B作为客户端的端口,并不是B在p2也侦听了
    这与udp是不一样的
    tcp要求:B必须在一个特定的端口pb侦听,然后告知S,A才能连ip2的pb端口
      

  18.   

    不太明白,你的意思是,如果两个客户端要连接,那两端都必须重新建过一个 socket 然后绑定一个新的端口来监听吗?
      

  19.   

    tcp下,一旦A要连B,B就是服务端了,B必须有侦听某个端口(pb),A才能作为一个客户端来连接,连接成功,A会得到一个动态的本地端口pa,实现:ip1:pa==>ip2:pb
      

  20.   

    看来是得为双方都开一个socket监听一个端口,不过我觉得,两者连接成功的可能性不大,明天试下,谢谢!
      

  21.   

    好贴,能否把你完成的程序DEMO贴出来,学习下。