请MrMengyi ,张无忌 或者 了解这样的问题的 请进 有个关于组播的问题想问,详细内容如下: ( 积分: 80 )

  • 主题发起人 主题发起人 980
  • 开始时间 开始时间
9

980

Unregistered / Unconfirmed
GUEST, unregistred user!
我的做法是使用有个固定ip的服务器。在服务器下面有很多不同ip地址的客户端(约1000个)。客户端通过internet和我的固定ip连接,服务器采集的数据2秒向这些客户端发送一次字符串 (相同的字符串)。
1:在internet上面可以使用 组播 吗?我看有的说 路游器多种多样不可以。希望有个明确答复。
2:组播的代码可不可以贴出来一段。让我参看一下。谢谢了/
3:怎样将那些 客户端 加到我的组播地址里来
4:可以详细介绍的也可以。因为我查看了关于这方面的帖子 ,还是不很明白。
有部分代码和说明最好
信箱是:liu980_980@163.com
 
我的做法是使用有个固定ip的服务器。在服务器下面有很多不同ip地址的客户端(约1000个)。客户端通过internet和我的固定ip连接,服务器采集的数据2秒向这些客户端发送一次字符串 (相同的字符串)。
1:在internet上面可以使用 组播 吗?我看有的说 路游器多种多样不可以。希望有个明确答复。
2:组播的代码可不可以贴出来一段。让我参看一下。谢谢了/
3:怎样将那些 客户端 加到我的组播地址里来
4:可以详细介绍的也可以。因为我查看了关于这方面的帖子 ,还是不很明白。
有部分代码和说明最好
信箱是:liu980_980@163.com
 
CUDPSocket::CUDPSocket(const char* sMutiCastAddr,unsigned int nPort)
{
if ((s = socket(AF_INET,SOCK_RAW,IPPROTO_IP)) == INVALID_SOCKET)
{
IF_DEBUG_COMMON(DebugPrint("create socket failed!"));
m_bOpen = false;
return;
}
struct ip_mreq ipmr;
SOCKADDR_IN local;
local.sin_family = AF_INET;
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_port = htons(nPort);

ipmr.imr_interface.s_addr = htonl(INADDR_ANY);
ipmr.imr_multiaddr.s_addr = inet_addr(sMutiCastAddr);

m_addrMutiCast.sin_family = AF_INET;
m_addrMutiCast.sin_addr.S_un.S_addr = inet_addr(sMutiCastAddr);
m_addrMutiCast.sin_port = htons(nPort);
const int on = 1;
if (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&on,sizeof(on)) == SOCKET_ERROR)
{
IF_DEBUG_COMMON(DebugPrint("setsockopt udp socket failed!"));
closesocket(s);
m_bOpen = false;
return;
}


/* if (bind(s,(sockaddr*)&local,sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
{
DWORD nError = GetLastError();

IF_DEBUG_COMMON(DebugPrint("bind udp socket failed : %d!", nError));
closesocket(s);
m_bOpen = false;
return;
}
*/
if (setsockopt(s,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char*)&ipmr,sizeof(ipmr)) == SOCKET_ERROR)
{
IF_DEBUG_COMMON(DebugPrint("setsockopt udp socket failed!"));
closesocket(s);
m_bOpen = false;
return;
}
int optval = 8;

if (setsockopt(s,IPPROTO_IP,IP_MULTICAST_TTL,(char*)&optval,sizeof(int)) == SOCKET_ERROR)
{
DWORD nError = GetLastError();

IF_DEBUG_COMMON(DebugPrint("setsockopt udp socket failed : %d!" ,nError ));
m_bOpen = false;
closesocket(s);
}
optval = 1;

/* if (setsockopt(s,IPPROTO_IP,IP_MULTICAST_LOOP,(char*)&optval,sizeof(int)) == SOCKET_ERROR)
{
closesocket(s);
m_bOpen = false;
}*/
m_bOpen = true;

}



int CUDPSocket::MutiCastMsg(char* sBuf, unsigned int nLen)
{
if (!m_bOpen)
{
return SOCKET_ERROR;
}

if (sBuf == NULL)
{
return 0;
}


int nRet = sendto(s,sBuf, nLen,0,(sockaddr*)&m_addrMutiCast,sizeof(sockaddr));
if (nRet == SOCKET_ERROR)
{
DWORD dwError = GetLastError();
IF_DEBUG_COMMON(DebugPrint("send to ERROR %d",dwError));
closesocket(s);
m_bOpen = false;
}
return nRet;
}
 
inet 可以
 
组播使用在internet上面并不是一个好办法,很多的路由器是不支持组播的(以前华为的路由器也不支持,现在不知道),就算现在有路由器支持,你也没有办法保证你的包所经过的路由都是支持组播协议的.
我觉得在WINDOWS下面还是使用TCP(或者UDP的PTOP)的IOCP模型的通用性好一些.至少不用担心你说的问题.
下面的是一段组播程序:
unit UdpSocket;

interface

uses
Classes, SysUtils, WinSock, Windows;

const
DEFAULTBUFFERSIZE = 16384;
MAXBUFFERSIZE = 63488;
MULTICAST_TTL = 10;

type
PIP_mreq = ^TIP_mreq;
TIP_mreq = record
imr_multiaddr : in_addr;
imr_interface : in_addr;
end;

ESocketError = class(Exception);

TSockSytle = (MultCastSend, MultCastRecv);

TUdpRecv = procedure(var Buf; Len: Integer;
FromIP: string; FromPort: u_Short) of object;

TUcpRecvThd = class(TThread)
private
FSocket : TSocket;
FBufSize : Integer;
FOnUdpRecv : TUdpRecv;
protected
procedure Execute; override;
end;

TUcpSocket = class(TObject)
private
class procedure StartSocket();
class procedure StopSocket();
private
FOnUdpRecv : TUdpRecv;
FLocalAddr : String;
FPort : u_Short;
FSocket : TSocket;
FAddrTo : TSockAddr;
FStyle : TSockSytle;
FBufSize : Integer;
FRemoteAddr : String;
FMCReq : TIP_mreq;
FUcpRecvThd : TUcpRecvThd;
private
procedure SetLocalAddr(Value: String);
procedure SetPort(Value: u_Short);
procedure SetSytle(Value: TSockSytle);
procedure SetBufSize(Value: Integer);
procedure SetRemoteAddr(Value: String);
public
function Send(var Buf; Len: Integer): Boolean;
procedure Busk();
published
property LocalAddr: String read FLocalAddr write SetLocalAddr;
property Port: u_Short read FPort write SetPort;
property Style: TSockSytle write SetSytle;
property BufSize: Integer read FBufSize write SetBufSize;
property RemoteAddr: String read FRemoteAddr write SetRemoteAddr;
property OnUdpRecv: TUdpRecv read FOnUdpRecv write FOnUdpRecv;
public
constructor Create();
destructor Destroy; override;
end;

implementation

{ TUcpSocket }

procedure TUcpSocket.Busk;
var
pPE : PProtoEnt;
Sock : TSocket;
SockAddrLocal, SockAddrRemote : TSockAddr;
nTTL, nReuseAddr : integer;
MCReq : TIP_mreq;
begin
pPE := GetProtoByName('UDP');

Sock := Socket(AF_INET, SOCK_DGRAM, pPE.p_proto);
if Sock = INVALID_SOCKET then
raise ESocketError.Create('创建Socket失败!');

nReuseAddr := 1;
if SetSockOpt(Sock, SOL_SOCKET, SO_REUSEADDR, @nReuseAddr, SizeOf(integer)) = SOCKET_ERROR then
begin
CloseSocket(Sock);
Exit;
end;

FillChar(SockAddrLocal, SizeOf(SockAddrLocal), 0);
SockAddrLocal.sin_family := AF_INET;
if FStyle = MultCastSend then
SockAddrLocal.sin_port := htons(0)
else
SockAddrLocal.sin_port := htons(Port);
SockAddrLocal.sin_addr.S_addr := Inet_Addr(PChar(FLocalAddr));
if Bind(Sock, SockAddrLocal, SizeOf(SockAddrLocal)) = SOCKET_ERROR then
begin
CloseSocket(Sock);
Exit;
end;

if FStyle = MultCastSend then
begin
//设置发送缓冲大小
if SetSockOpt(Sock, SOL_SOCKET, SO_SNDBUF,
@FBufSize, SizeOf(Integer)) = SOCKET_ERROR then
begin
CloseSocket(Sock);
Exit;
end;

//设置发送时的参数
if SetSockOpt(Sock, IPPROTO_IP, IP_MULTICAST_IF, @(SockAddrLocal.sin_addr),
SizeOf(In_Addr)) = SOCKET_ERROR then
begin
CloseSocket(Sock);
Exit;
end;
nTTL := MULTICAST_TTL;
if SetSockOpt(Sock, IPPROTO_IP, IP_MULTICAST_TTL, @nTTL, SizeOf(integer)) = SOCKET_ERROR then
begin
CloseSocket(Sock);
Exit;
end;

FillChar(SockAddrRemote, SizeOf(SockAddrRemote), 0);
SockAddrRemote.sin_family := AF_INET;
SockAddrRemote.sin_port := htons(Port);

SockAddrRemote.sin_addr.S_addr := Inet_Addr(PChar(FRemoteAddr));

FAddrTo := SockAddrRemote;
end else //接收
begin
//设置接收缓冲大小
if SetSockOpt(Sock, SOL_SOCKET, SO_RCVBUF, @fBufSize, SizeOf(integer)) = SOCKET_ERROR then
begin
CloseSocket(Sock);
Exit;
end;

//加入组
MCReq.imr_multiaddr.S_addr := Inet_Addr(PChar(FRemoteAddr));
MCReq.imr_interface.S_addr := Inet_Addr(PChar(FLocalAddr));
if SetSockOpt(Sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, @MCReq,
SizeOf(TIP_mreq)) = SOCKET_ERROR then
begin
CloseSocket(Sock);
Exit;
end;

fMCReq := MCReq;
end;

FSocket := Sock;

if FStyle = MultCastRecv then
begin
FUcpRecvThd.FSocket := FSocket;
FUcpRecvThd.FBufSize := FBufSize;
FUcpRecvThd.FOnUdpRecv := FOnUdpRecv;
FUcpRecvThd.Resume;
end;
end;

constructor TUcpSocket.Create;
begin
FOnUdpRecv := nil;
FLocalAddr := '127.0.0.1';
FPort := 0;
FStyle := MultCastRecv;
FBufSize := DEFAULTBUFFERSIZE;
FUcpRecvThd := TUcpRecvThd.Create(true);
end;

destructor TUcpSocket.Destroy;
begin
CloseSocket(FSocket);
FUcpRecvThd.Free;
inherited;
end;

function TUcpSocket.Send(var Buf; Len: Integer): Boolean;
begin
Result := false;
if SendTo(FSocket, Buf, Len, MSG_DONTROUTE, FAddrTo,
SizeOf(FAddrTo)) <> SOCKET_ERROR then
Result := true;
end;

procedure TUcpSocket.SetLocalAddr(Value: String);
begin
FLocalAddr := Value;
end;

procedure TUcpSocket.SetBufSize(Value: Integer);
begin
FBufSize := Value;
end;

procedure TUcpSocket.SetPort(Value: u_Short);
begin
FPort := Value;
end;

procedure TUcpSocket.SetRemoteAddr(Value: String);
var
nMCAddr : Cardinal;
begin
FRemoteAddr := Value;
nMCAddr := ntohl(inet_addr(PChar(FRemoteAddr)));
if not ((nMCAddr <= $efffffff) and (nMCAddr >= $e0000100)) then
raise ESocketError.Create('无效的组播地址!');
end;

procedure TUcpSocket.SetSytle(Value: TSockSytle);
begin
FStyle := Value;
end;

class procedure TUcpSocket.StartSocket;
var
WsData: TWSAData;
err: Integer;
begin
err := WSAStartup(MAKEWORD(2, 2), WsData);
if err <> 0 then
raise ESocketError.Create('不能使用SOCKET服务!');

if ( LOBYTE( WsData.wVersion ) <> 2 ) or
( HIBYTE( WsData.wVersion ) <> 2 ) then
raise ESocketError.Create('没有找到所需要的SOCKET版本!');
end;

class procedure TUcpSocket.StopSocket;
begin
WSACleanup;
end;

{ TUcpRecvThd }

procedure TUcpRecvThd.Execute;
var
readFDs : TFDSet;
nRecved, nAddrLen: integer;
Buf : array [0..MAXBUFFERSIZE] of Byte;
SockFrom : TSockAddr;
begin
Priority := tpHighest;
while not Terminated do
begin
nAddrLen := SizeOf(SockFrom);
FD_ZERO(readFDs);
FD_SET(FSocket, readFDs);

Select(0, @readFDs, nil, nil, nil);

if FD_ISSET(FSocket, readFDs) then
begin
nRecved := RecvFrom(FSocket, buf, FBufSize, 0, SockFrom, nAddrLen);

if Assigned(FOnUdpRecv) then
FOnUdpRecv(Buf, nRecved, string(Inet_Ntoa(SockFrom.sin_addr)),
Cardinal(Ntohs(SockFrom.sin_port)));
end;
end;
end;

initialization
TUcpSocket.StartSocket;
finalization
TUcpSocket.StopSocket;

end.
调用如下:

unit Demo;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, UdpSocket, WinSock;

const
MULTCASTADDR: String = '225.0.1.177';
MULTCASTPORT: Integer = 10000;

type
TUdpSocketDemo = class(TForm)
edtSendText: TEdit;
meoRecvText: TMemo;
cmdSend: TButton;
cmdInit: TButton;
cmdExit: TButton;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure cmdExitClick(Sender: TObject);
procedure cmdSendClick(Sender: TObject);
procedure cmdInitClick(Sender: TObject);
private
{ Private declarations }
FMultCastUdpSend: TUcpSocket; //Send Socket
FMultCastUdpRecv: TUcpSocket; //Recv Socket
public
{ Public declarations }

procedure OnUdpRecv(var Buf; Len: Integer;
FromIP: string; FromPort: u_Short);
end;

var
UdpSocketDemo: TUdpSocketDemo;

implementation

{$R *.dfm}

procedure TUdpSocketDemo.cmdInitClick(Sender: TObject);
begin
FMultCastUdpSend := TUcpSocket.Create;
FMultCastUdpSend.LocalAddr := '172.18.2.111';
FMultCastUdpSend.Port := MULTCASTPORT;
FMultCastUdpSend.Style := MultCastSend;
FMultCastUdpSend.RemoteAddr := MULTCASTADDR;
FMultCastUdpSend.Busk;

FMultCastUdpRecv := TUcpSocket.Create;
FMultCastUdpRecv.LocalAddr := '172.18.2.111';
FMultCastUdpRecv.Port := MULTCASTPORT;
FMultCastUdpRecv.Style := MultCastRecv;
FMultCastUdpRecv.RemoteAddr := MULTCASTADDR;
FMultCastUdpRecv.OnUdpRecv := OnUdpRecv;
FMultCastUdpRecv.Busk;

cmdInit.Enabled := false;
end;

procedure TUdpSocketDemo.cmdSendClick(Sender: TObject);
var
Buf: array of Char;
Len: Integer;
begin
Len := Length(edtSendText.Text);
SetLength(Buf, Len);
StrPCopy(@Buf[0], edtSendText.Text);

FMultCastUdpSend.Send(Buf, Len);
end;

procedure TUdpSocketDemo.cmdExitClick(Sender: TObject);
begin
Close;
end;

procedure TUdpSocketDemo.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FMultCastUdpSend.Free;
end;

procedure TUdpSocketDemo.OnUdpRecv(var Buf; Len: Integer; FromIP: string;
FromPort: u_Short);
begin
meoRecvText.Lines.Add(String(Buf));
end;

end.
使用的时候注意防火墙.
 
谢谢你。请问 视频会议的 我看有使用组播的 ,他们是怎样实现的呢。
他们可以在任何网络上面使用
 
如果真的有这种情况,那就等其它FW来说说吧,呵呵!
 
to:寻路
不是这个意思。我的做法是这样的 。我现在的服务器是普通pc机器。三洋2.0的cpu 、256的内存,现在我使用tcp/ip的,有50个客户端。服务器的速度就不行了(客户和服务器连接,然后身份验证,服务器采集信息,向客户端发送)
你说的 “TCP(或者UDP的PTOP)的IOCP模型的通用性” 这些我也再查。
你还有什么好的方法 ,解决问题就可以。谢了。
可以把你上面的组播代码 发到我的信箱里吗:liu980_980@163.com
 
视频会议 的分散式会议的确是组播的
但一般 视频会议 是需要配路由器的
 
to :djh_djh你说的 其实视频会议 在自己的网络(自己一个相对独立的internt,可能没有表达明白)使用的是组播,对于一个不属于他们的网络(任何一个能够上网的机器),他们不是使用这个组播,我说的对吗。

想使用的话必须 “配路由器” 是这样的吧

现在我的系统已经运行测试过程,还没有正式使用,使用tcp/ip 50个客户 服务器的速度就慢了 ,我的需要1000多个呢 ,方法怎样解决。
拜托各位了
 
哪个是一个一个发的吧
组波受到路由器的影响
 
50个就慢了,只能说明你的服务端写得不好!
上面的代码已经是完整的了,自己整理一下吧,不要太懒了!
 
我服务器的代码是这样的
他其实就是一个接收发送的中转 ,别的没有作什么。
我使用listbox1
客户一连接就
ListBox1.Items.add(Socket.RemoteAddress);
断开就
Listbox1.Items.Delete(Listbox1.Items.IndexOf(Socket.RemoteAddress));
下面是发送的语句
for i:=0 to listbox1.Items.Count-1 do
begin
ServerSocket2.socket.connections.sendtext(trim(phondz+information));
end;
服务器工作可以说非常简单,一个是机器多了速度满。二是这样依次发送,多了肯定有个延时。
请高手门支招
 
对 对于基于H.323的视频会议,在非集中式时,是用组播的,

但是 一般公司的产品都需要专门组网,如果要在Internet开视频会议,组播是很不可靠的

你这个程序是写来玩的还是正式的
  呵呵,这样写法当然慢了,如果你要大量的用户
如果用TCP 就要用异步IO, 否则用UDP
如果传媒体流, 最好还要实现一个RTP/RTCP
<windows网络编程> 讲得详细的,看一下就行了,不难的
 
谢谢 :djh_djh 了,这个可以说正式的 ,对这个也不是很懂 ,现在属于测试过程 ,看到你讲的也很详细了,“windows网络编程” 这个本书我有 就是没有里面的代码 我看还都是vc的 ,刚开始看 我查查 相关 异步IO的问题了。你要是有时间,就详细点说说。谢谢了。
 
求个多线程 并发的例子 或者详细介绍 谢谢了
 
查查我以答的问题,里面有一个!
 
今天才有时间
to :寻路 你说的是这个吗?
http://www.delphibbs.com/delphibbs/dispq.asp?lid=2713841
 
后退
顶部