请问,如何在 socket 中指定使用 ipx 协议?(100分)

  • 主题发起人 主题发起人 qkl
  • 开始时间 开始时间
Q

qkl

Unregistered / Unconfirmed
GUEST, unregistred user!
我知道在 sock 函数中可以指定建立一个 socket 的协议,但我不明白具体的使用和数值。
谢谢
 
WinSock2支持的协议类型包括:
#define IPPROTO_IP 0 /* dummy for IP */
#define IPPROTO_ICMP 1 /* control message protocol */
#define IPPROTO_IGMP 2 /* internet group management protocol */
#define IPPROTO_GGP 3 /* gateway^2 (deprecated) */
#define IPPROTO_TCP 6 /* tcp */
#define IPPROTO_PUP 12 /* pup */
#define IPPROTO_UDP 17 /* user datagram protocol */
#define IPPROTO_IDP 22 /* xns idp */
#define IPPROTO_IPV6 41 /* IPv6 */
#define IPPROTO_ND 77 /* UNOFFICIAL net disk proto */
#define IPPROTO_ICLFXBM 78
...
详细信息可在WinSock.h和WinSock2.h中找到

我估计socket不支持IPX协议,我的任意一本socket编程书里都没有提到它能支持IPX协议。
 
[:)]谢谢 Sachow, 我敢肯定 socket 支持 ipx,我有 vc 的代码,而且也有一段实现的代码:
in wsipx.h
/*
* This is the structure of the SOCKADDR structure for IPX and SPX.
*
*/

typedef struct sockaddr_ipx {
short sa_family;
char sa_netnum[4];
char sa_nodenum[6];
unsigned short sa_socket;
} SOCKADDR_IPX, *PSOCKADDR_IPX,FAR *LPSOCKADDR_IPX;

/*
* Protocol families used in the "protocol" parameter of the socket() API.
*
*/

#define NSPROTO_IPX 1000
#define NSPROTO_SPX 1256
#define NSPROTO_SPXII 1257
...
m_sClientSocket = socket(AF_IPX, SOCK_STREAM, NSPROTO_SPX);
...
connect(m_sClientSocket, (LPSOCKADDR)&IPX_serverAddr, sizeof(IPX_serverAddr))
...
现在问题是
为什么 delphi 中没有定义这些常量?
为什么 delphi 自带的 socket 控件不能选择协议?
最重要是,哪位朋友有实现的代码或控件?
 
根据你的提示,我也找到了wsipx.h文件,如此说来,WinSock2确实是支持IPX协议的。不
瞒你说,我手头的Socket编程书籍都是讲Unix下的socket编程的,而且全讲的是TCP/IP,
没注意到IPX方面的。

早些时候我分析TCustomWinSocket的代码,就发现它实际上只是将协议绑定为IPPROTO_IP,
所以根本就不提供协议类型的选择。我想这大概是为了简化控件的使用,否则如果将地址
类型、socket类型、协议类型都封装为可选的属性的化,其编程的复杂程序也就跟直接用
API差不多了。
上面那段代码,既然VC做得到,Delphi同样做得到,但整个编程就都得用API了,不能借助
于控件。如果有兴趣的话,我们做做试试。
下面是我根据wsipx.h改的:

unit wsipx;

interface

type
SOCKADDR_IPX = record
sa_family: SmallInt;
sa_netnum: array [0..3] of Char;
sa_nodenum: array [0..6] of Char;
sa_socket: Word;
end;
PSOCKADDR_IPX = ^SOCKADDR_IPX;

const
NSPROTO_IPX = 1000;
NSPROTO_SPX = 1256;
NSPROTO_SPXII = 1257;

implementation

end.
 
我觉得只有用控件才能更好更方便的被 delphi 开发员使用,
但是要修改自带的 socket 控件需要从 TAbstractSocket 层次修改,目标是增加一个和协议有关的属性项,
那将可能牵涉整个 TSocket 结构,将要产生新的 TSocket 控件,不知道可行度怎样。
另外,我发现 delphi6 中的 indy 控件使用是另外的 Socket 包装结构,好象 indy 可以使用指定协议,但我不敢肯定。
 
我见过有IPX控件的,你找找看把,如果实在不行就用API写
 
如果自己封装的话,工作量确实很大。我查了一下帮助,发现CLX的TBaseSocket好像可以选
协议,TTcpClient和TTcpServer就是继承自它的,我从来没有用过。
它在Windows下的实现也是基于WinSock的,所以只要引用了如上面修改的wsipx单元,
应该是可行的。
 
我已经解决问题了,,
我改些了 TSocket 类增加了对 IPX 的支持,
现在还有一些需要改进的地方:
异步的实现、GetSocketAddr 返回 IPX Address 的实现
 
已经完成异步的实现,,
现在的问题是如何取得一个 socket 的 IPX 地址?
 
查一下MSDN,里面有现成的例子。
SOCKSPX.C
/******************************************************************************/
* This is a part of the Microsoft Source Code Samples.
* Copyright 1996 - 1998 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
/******************************************************************************/


/*
Module Name:

sockspx.c

Abstract:

This module illustrates the Win32 Winsock APIs over IPX/SPX protocol
sequence.

This example implements a client and a server. This example can use IPX,
SPX as well as SPXII protocol sequences. The example has a number command
line options. For example,

-s To run the example as a server.

-c To run the example as a client.

-e <Endpoint> To specify an end point of your choice. This is a mandatory
parameter. Servers use this as the socket number to listen on, clients use
it as the socket number to connect to, on a specified host.

-n <ServerIpxAddress> To specify the server's IPX address. This is used by
clients. The address must be spcified as <NetworkNumber.NodeNumber>
format, for example AABBCCDD.AABBCCDDEEFF.

-l <LocalIpxAddress> To specify the local IPX address. This is used by
clients and servers. The address must be spcified as <NetworkNumber.
NodeNumber> format, for example AABBCCDD.AABBCCDDEEFF. If an IPX address
is not specified the created sockets are bound to the default interface,
00000000.000000000000.

-p <d or s or p> To specify the protocol sequence to be used.
'd' - datagram support, in this case IPX protocol sequence is used.
's' - SOCK_STREAM/SPXII protocol sequence is used(default protocol).
'p' - SOCK_SEQPACKET/SPXII protocol sequence isused.

-m To Enumerate Local Addresses. This example can be used only to
enumerate the local IPX adapters. This may be important before running the
client to know the server's IPX address.

To run the application as a server, the following command line can be
specified:

sockspx -s -e 8000 -p s

To run the application to act as a client, the following command line can be
specified:

sockspx -c -n AABBCCDD.AABBCCDDEEFF -e 8000 -p s

To enumerate the local IPX adapters, the following command line will have
to be specified:

sockspx -m


Author:

Rajesh Dadhia (rajeshd) 05-Mar-96

Revision History:

*/

#include <stdio.h>
#include <windows.h>
#include <winsock.h>
#include <wsipx.h>
#include <wsnwlink.h>

#define MAX_DATA_LEN 80

BOOL __stdcall
CtrlCHandler (
DWORD dwEvent
);

void __stdcall
EnumerateAdapters ( void );

void __stdcall
DoServer ( void );

void __stdcall
DoClient ( void );

void __stdcall
DoStartup ( void );

void __stdcall
CreateSocket ( void );

void __stdcall
BindSocket (
SOCKADDR_IPX *psa,
LPSTR lpsAddress,
LPSTR lpsEndpoint
);

void _stdcall
FillIpxAddress (
SOCKADDR_IPX *psa,
LPSTR lpsAddress,
LPSTR lpsEndpoint
);

INT __stdcall
SendData (
SOCKET s,
CHAR *pchBuffer
);

INT __stdcall
ReceiveData (
SOCKET s,
CHAR *pchBuffer
);

INT __stdcall
SendDatagram (
SOCKET s,
CHAR *pchBuffer,
SOCKADDR_IPX *psa
);

INT __stdcall
ReceiveDatagarm (
SOCKET s,
CHAR *pchBuffer,
SOCKADDR_IPX *psa,
INT *pcb );

void __stdcall
DoCleanup ( void );

void __stdcall
CheckParameters (
INT argc,
CHAR **argv
);

BOOL __stdcall
CheckProtocol(
CHAR chProtocol
);

void __stdcall
Usage (
CHAR *pszProgramName
);

void __stdcall
PrintError (
CHAR *lpszRoutine,
CHAR *lpszCallName,
DWORD dwError
);

void __stdcall
PrintIpxAddress(
CHAR *lpsNetnum,
CHAR *lpsNodenum
);

void __stdcall
AtoH(
CHAR *szDest,
CHAR *szSource,
INT iCount
);

UCHAR __stdcall
BtoH(
CHAR ch
);

//
// Global Variables
//

// Role of the Application
BOOL fServer = TRUE,

// Enumerate the Local Adapters
fEnumerate = FALSE,

// WSAStartup () was sucessfull
fStarted = FALSE;

// Global socket handles
SOCKET sock = INVALID_SOCKET,
newsock = INVALID_SOCKET;

// Server's IPX address string
CHAR *pszServerAddress,

// Local IPX address string
*pszLocalAddress,

// Server's Endpoint(socket) string
*pszServerEndpoint,

// Protocol type (Datagram, Stream, Sequenced Packet)
chProtocol = 's';

void __cdecl
main (
INT argc,
CHAR **argv
)
{

//
// Install the CTRL+BREAK Handler
//
if ( FALSE == SetConsoleCtrlHandler ( (PHANDLER_ROUTINE) CtrlCHandler,
TRUE
) )
{
PrintError ( "main", "SetConsoleCtrlHandler", GetLastError ( ) );
}

//
// Parse the command line parameters
//
CheckParameters ( argc, argv );

//
// Check to see if the role of the application is to enumerate local
// adapters
//
if ( TRUE == fEnumerate )
{
EnumerateAdapters ( );
return;
}

//
// Act as a server
//
if( TRUE == fServer )
{
DoServer ( );
return;
}

//
// Act as client
//
else
{
DoClient ( );
return;
}
}

//
// CtrlCHandler () intercepts the CTRL+BREAK or CTRL+C events and calls the
// cleanup routines
//
BOOL __stdcall
CtrlCHandler (
DWORD dwEvent
)
{

if ( ( CTRL_C_EVENT == dwEvent ) || ( CTRL_BREAK_EVENT == dwEvent ) )
{
DoCleanup ( );
}

return FALSE;
}

//
// EnumerateAdapters () will enumerate the available IPX adapters and print
// the addresses
//
void __stdcall
EnumerateAdapters ( void )
{
SOCKADDR_IPX sa_ipx;
IPX_ADDRESS_DATA ipx_data;
INT iRetVal, cb, nAdapters, i=0;

//
// Initialize the Winsock 1.1 DLL
//
DoStartup ( );

//
// Create a local socket
//
chProtocol = 'd';
CreateSocket ( );

//
// Bind to a local address and endpoint
//
BindSocket ( &amp;sa_ipx, NULL, NULL );

//
// Call getsockopt() see the total number of adapters
//
cb = sizeof ( nAdapters );
iRetVal = getsockopt ( sock,
NSPROTO_IPX,
IPX_MAX_ADAPTER_NUM,
(CHAR *) &amp;nAdapters,
&amp;cb
);

if ( SOCKET_ERROR == iRetVal )
{
PrintError ( "EnumerateAdapters",
"getsockopt",
WSAGetLastError ( )
);
}
fprintf ( stdout, "Total number of adapters -> %d/n", nAdapters );

//
// Get the address of each adapter
//
while ( nAdapters > 0 )
{
memset ( &amp;ipx_data, 0, sizeof ( ipx_data ) );
ipx_data.adapternum = (nAdapters -1);
cb = sizeof ( ipx_data );

iRetVal = getsockopt ( sock,
NSPROTO_IPX,
IPX_ADDRESS,
(CHAR *) &amp;ipx_data,
&amp;cb
);

if ( SOCKET_ERROR == iRetVal )
{
PrintError ( "EnumerateAdapters",
"getsockopt",
WSAGetLastError ( )
);
}

//
// Print each address
//
PrintIpxAddress ( ipx_data.netnum, ipx_data.nodenum );
nAdapters--;
}

//
// Call the cleanup routine
//
DoCleanup ( );
return;
}

//
// DoServer () performs the connection-less/connection-oriented server
// related tasks
//
void __stdcall
DoServer ( void )
{
// Address structures for the client and the server
SOCKADDR_IPX sa_ipx, sa_ipx_client;

// Buffer for the received/sent data
CHAR chBuffer[MAX_DATA_LEN];

INT iRetVal, cb;

DoStartup ( );

CreateSocket ( );

//
// Bind to a local address and endpoint
//
BindSocket ( &amp;sa_ipx, pszLocalAddress, pszServerEndpoint);

//
// Check the Specified protocol. Call listen(), accept() if a connection
// oriented protocol is specified
//
if ( 'd' != chProtocol )
{
iRetVal = listen ( sock, 5 );

if ( SOCKET_ERROR == iRetVal )
{
PrintError ( "DoServer", "listen", WSAGetLastError ( ) );
}

fprintf ( stdout, "Waiting for a Connection.../n");
fprintf ( stdout, "Press <CTRL+C> or <CTRL+BREAK> to exit/n");
//
// Wait for a connection
//
cb = sizeof ( sa_ipx_client );
newsock = accept ( sock,
(SOCKADDR *) &amp;sa_ipx_client,
&amp;cb
);

if ( INVALID_SOCKET == newsock )
{
PrintError ( "DoServer", "accept", WSAGetLastError ( ) );
}

//
// Print the address of connected client
//
fprintf ( stdout, "Connected to Client Address - " );
PrintIpxAddress ( sa_ipx_client.sa_netnum, sa_ipx_client.sa_nodenum );

//
// Receive data on newly created socket
//
iRetVal = ReceiveData ( newsock, chBuffer );

//
// Print the contents of received data
//
chBuffer[iRetVal] = '/0';
fprintf ( stdout,"%d bytes of data received->%s/n",iRetVal, chBuffer );
strcpy ( chBuffer, "Hello SPX Client" );

//
// Send data on newly created socket
//
iRetVal = SendData ( newsock, chBuffer );
fprintf ( stdout, "%d bytes of data sent/n", iRetVal );
}
//
// Server will receive and send datagrams
//
else
{
//
// Receive a datagram on the bound socket
//
cb = sizeof ( sa_ipx_client );
iRetVal = ReceiveDatagarm ( sock, chBuffer, &amp;sa_ipx_client, &amp;cb );

//
// Print the contents of received datagram and the senders address
//
fprintf ( stdout, "Message Received from Client Address - " );
PrintIpxAddress( sa_ipx_client.sa_netnum, sa_ipx_client.sa_nodenum );
chBuffer[iRetVal] = '/0';
fprintf( stdout, "Data Received->%s/n", chBuffer );
fprintf( stdout,"%d bytes of data received->%s/n",iRetVal, chBuffer );

//
// Send a datagram on the bound socket to the client
//
strcpy ( chBuffer, "Hello IPX Client" );
iRetVal = SendDatagram (sock, chBuffer, &amp;sa_ipx_client );
fprintf( stdout, "%d bytes of data sent/n", iRetVal );
}

//
// Call the cleanup routine
//
DoCleanup ( );
return;
}

//
// DoClient () performs the connection-less/connection-oriented client
// related tasks
//
void __stdcall
DoClient ( void )
{
// Address structures for the client and the server
SOCKADDR_IPX sa_ipx, sa_ipx_server;

// Buffer for the received/sent data
CHAR chBuffer[MAX_DATA_LEN];

INT iRetVal, cb;

DoStartup ( ) ;

CreateSocket ( );

//
// Bind to a local address and endpoint
//
BindSocket ( &amp;sa_ipx, pszLocalAddress, NULL);


if ( NULL == pszServerEndpoint )
{
fprintf ( stdout, "Server Endpoint must be specified....Exiting/n");
DoCleanup ( );
exit ( 1 );
}

//
// Fill the sa_ipx_server address address with server address and endpoint
//
if ( NULL != pszServerAddress )
{
FillIpxAddress ( &amp;sa_ipx_server, pszServerAddress, pszServerEndpoint );
}
else
{
fprintf ( stdout, "Server Address must be specified....Exiting/n");
DoCleanup ( );
exit ( 1 );
}

//
// Check the Specified protocol. Call connect() if a connection oriented
// protocol is specified
//
if ( chProtocol != 'd' )
{
fprintf(stdout, "Connecting to Server -");
PrintIpxAddress ( sa_ipx_server.sa_netnum, sa_ipx_server.sa_nodenum );

//
// Connect to the server
//
iRetVal = connect ( sock,
(SOCKADDR *) &amp;sa_ipx_server,
sizeof sa_ipx_server
);

if ( SOCKET_ERROR == iRetVal )
{
PrintError ( "DoClient", "connect", WSAGetLastError ( ) );
}

fprintf ( stdout, "Connected to Server Address - " );
PrintIpxAddress( sa_ipx_server.sa_netnum, sa_ipx_server.sa_nodenum );

//
// Send data to the specfied server
//
strcpy ( chBuffer, "Hello SPX Server" );
iRetVal = SendData ( sock, chBuffer );
fprintf( stdout, "%d bytes of data sent/n", iRetVal );

//
// Receive data from the server
//
iRetVal = ReceiveData ( sock, chBuffer );

//
// Print the contents of received data
//
chBuffer[iRetVal] = '/0';
fprintf( stdout, "%d bytes of data received->%s/n", iRetVal,chBuffer);
}
else
{
//
// Send a datagram to the specified server
//
strcpy ( chBuffer, "Hello IPX Server" );
iRetVal = SendDatagram ( sock, chBuffer, &amp;sa_ipx_server );
fprintf ( stdout, "%d bytes of data sent/n", iRetVal );

//
// Receive a datagram from the server
//
cb = sizeof sa_ipx_server;
iRetVal = ReceiveDatagarm ( sock, chBuffer, &amp;sa_ipx_server, &amp;cb );

//
// Print the contents of received data
//
chBuffer[iRetVal] = '/0';
fprintf ( stdout, "%d bytes of data received->%s/n",iRetVal,chBuffer);
}

//
// Call the cleanup routine
//
DoCleanup ( );

return;
}

//
// DoStartup() initializes the Winsock DLL with Winsock version 1.1
//
void __stdcall
DoStartup ( void )
{
WSADATA wsaData;
INT iRetVal;

iRetVal = WSAStartup ( MAKEWORD ( 1,1 ), &amp;wsaData );

if ( 0 != iRetVal)
{
PrintError ( "DoStartup", "WSAStartup", iRetVal );
}

/* Set the global flag */
fStarted = TRUE;

return;
}

//
// CreateSocket() creates an endpoint (socket) and assigns the returned value
// from socket() to the global socket descriptor 'sock'. The actual protocol
// specified on the command line is checked, in order to make the socket()
// call correctly.
//
void __stdcall
CreateSocket ( void )
{
sock = socket ( AF_IPX,
chProtocol == 'd' ? SOCK_DGRAM :
( chProtocol == 's' ? SOCK_STREAM : SOCK_SEQPACKET),
chProtocol == 'd' ? NSPROTO_IPX : NSPROTO_SPXII
);

if ( INVALID_SOCKET == sock )
{
PrintError ( "CreateSocket", "socket", WSAGetLastError ( ) );
}

return;
}

//
// BindSocket() binds the global socket descriptor 'sock' to the specified
// address. If an endpoint is specified it uses that or it binds to a system
// assigned port.
//
void __stdcall
BindSocket (
SOCKADDR_IPX *psa,
LPSTR lpsAddress,
LPSTR lpsEndpoint
)
{
INT iRetVal;

//
// Fill the givenSOCKADDR_IPX structure
//
FillIpxAddress ( psa, lpsAddress, lpsEndpoint );

iRetVal = bind ( sock,
(SOCKADDR *) psa,
sizeof (SOCKADDR_IPX)
);

if ( SOCKET_ERROR == iRetVal )
{
PrintError ( "BindSocket", "bind", WSAGetLastError ( ) );
}

//
// Print the address we are bound to. If a particular interface is not
// mentioned in the BindSocket() call, this may print the address as
// 00000000.0000000000000000. This is because of the fact that an
// interface is picked only when the actual connection establishment
// occurs, in case of connection oriented socket.
//
fprintf ( stdout, "Bound to Local Address - " );
PrintIpxAddress( psa->sa_netnum, psa->sa_nodenum );

return;
}

//
// FillIpxAddress() fills a structure of type SOCKADDR_IPX with relevant
// address-family, network number, node number and socket (endpoint)
// parameters.
//
void _stdcall
FillIpxAddress (
SOCKADDR_IPX *psa,
LPSTR lpsAddress,
LPSTR lpsEndpoint
)
{
// Location of the separator
LPSTR pszPoint;

ZeroMemory ( psa, sizeof ( SOCKADDR_IPX ) );

psa->sa_family = AF_IPX;

//
// Check if an address is specified
//
if ( NULL != lpsAddress )
{
//
// Get the offset for node number/network number separator
//
pszPoint = strchr ( lpsAddress, '.' );

if ( NULL == pszPoint )
{
fprintf ( stderr, "IPX Address does not have a separator/n");
DoCleanup ( );
exit ( 1 );
}

//
// covert the address in the string format to binary format
//
AtoH ( (CHAR *) psa->sa_netnum, lpsAddress, 4 );
AtoH ( (CHAR *) psa->sa_nodenum, pszPoint + 1, 6 );

}

if ( NULL != lpsEndpoint )
{
psa->sa_socket = (USHORT) atoi ( lpsEndpoint );
}

return;
}

//
// SendData() is generic rotuine to send some data over a
// connection-oriented IPX socket.
//
INT __stdcall
SendData (
SOCKET s,
CHAR *pchBuffer
)
{
INT iRetVal;

iRetVal = send ( s,
pchBuffer,
strlen ( pchBuffer ),
0
);

if ( SOCKET_ERROR == iRetVal )
{
PrintError ( "SendData", "send", WSAGetLastError ( ) );
}

//
// return the total number of bytes sent
//
return iRetVal;
}

//
// ReceiveData() is generic rotuine to receive some data over a
// connection-oriented IPX socket.
//
INT __stdcall
ReceiveData (
SOCKET s,
CHAR *pchBuffer
)
{
INT iRetVal;

iRetVal = recv ( s,
pchBuffer,
MAX_DATA_LEN,
0
);

if ( SOCKET_ERROR == iRetVal )
{
PrintError ( "ReceiveData", "recv", WSAGetLastError ( ) );
}

//
// return the total number of bytes received
//
return iRetVal;
}

//
// SendDatagram() is generic rotuine to send a datagram to a
// specifid host.
//
INT __stdcall
SendDatagram (
SOCKET s,
CHAR *pchBuffer,
SOCKADDR_IPX *psa
)
{
INT iRetVal;

iRetVal = sendto ( s,
pchBuffer,
strlen ( pchBuffer ),
0,
(SOCKADDR *) psa,
sizeof ( SOCKADDR_IPX )
);

if ( SOCKET_ERROR == iRetVal )
{
PrintError ( "SendDatagram", "sendto", WSAGetLastError ( ) );
}

/* return the total number of bytes sent in the datagram */
return iRetVal;
}

//
// ReceiveDatagram() is generic rotuine to receive a datagram from a
// specifid host.
//
INT __stdcall
ReceiveDatagarm (
SOCKET s,
CHAR *pchBuffer,
SOCKADDR_IPX *psa,
INT *pcb )
{
INT iRetVal;

iRetVal = recvfrom ( s,
pchBuffer,
MAX_DATA_LEN,
0,
(SOCKADDR *) psa,
pcb
);

if ( SOCKET_ERROR == iRetVal )
{
PrintError ( "ReceiveDatagram", "recvfrom", WSAGetLastError ( ) );
}

//
// return the total number of bytes received in the datagram
//
return iRetVal;
}

//
// DoCleanup () will close the sockets which were opened successfully using
// a call to socket (). Additionally, it will call WSACleanup (), if a call
// to WSAStartup () was made successfully.
//
void __stdcall
DoCleanup ( void )
{
if ( INVALID_SOCKET != sock )
{
closesocket ( sock );
}

if ( INVALID_SOCKET != newsock )
{
closesocket ( sock );
}

if ( TRUE == fStarted )
{
WSACleanup ( );
}

fprintf ( stdout, "DONE/n");

return;
}

//
// CheckParameters() parses the command line parametrs.
//
void __stdcall
CheckParameters (
INT argc,
CHAR **argv
)
{
INT i;

for ( i = 1; i < argc; i++ )
{
if ( ( *argv == '-') || ( *argv == '/' ) )
{
switch ( tolower ( *( argv+1 ) ) )
{

//
// Role of the application - server
//
case 's':
fServer = TRUE;
break;

//
// Role of the application - client
//
case 'c':
fServer = FALSE;
break;

//
// Store a pointer to the server endpoint
//
case 'e':
pszServerEndpoint = argv[++i];
break;

//
// Store a pointer to the server address
//
case 'n':
pszServerAddress = argv[++i];
break;

//
// Store a pointer to the local address
//
case 'l':
pszLocalAddress = argv[++i];
break;


//
// Set the flag to indicate enumeration of local adapters
//
case 'm':
fEnumerate = TRUE;
break;

//
// Read and validate the protocol specified
//
case 'p':
chProtocol = tolower ( *argv[++i] );
if ( FALSE == CheckProtocol ( chProtocol ) )
{
fprintf ( stderr, "UnKnown protcol specified/n/n");
Usage ( argv[0] );
}
break;
//
// Help
//
case 'h':
case '?':
default:
Usage ( argv[0] );
}
}
//
// Help
//
else
Usage ( argv[0] );
}
return;
}

//
// CheckProtocol() checks if a valid protocol is specified on the command
// line.
//
BOOL __stdcall
CheckProtocol(
CHAR chProtocol
)
{
if ( 'd' != chProtocol &amp;&amp; 's' != chProtocol &amp;&amp; 'p' != chProtocol )
{
return FALSE;
}

return TRUE;
}

//
// Display the usage of command line parameters.
//
void __stdcall
Usage (
CHAR *pszProgramName
)
{
fprintf ( stderr,"Usage: %s/n", pszProgramName );
fprintf ( stderr,
"/t-s or -c (s - server, c - client, default - server)/n" );
fprintf ( stderr, "/t-e <Endpoint>/n" );
fprintf ( stderr, "/t-n <ServerIpxAddress>/n" );
fprintf ( stderr, "/t-l <LocalIpxAddress>/n" );
fprintf ( stderr,
"/t-p <d or s or p> ( d - datagram, s - stream, p - sequenced packet)/n" );
fprintf ( stderr, "/t-m To Enumerate Local Addresses/n" );

exit ( 1 );
}

//
// PrintError () is a generic routine to print the Winsock or Win32
// error codes for the errors occurred during relevant calls.
// If an error occurs, the error code is printed, cleanup routine is
// called and the application exits.
//
void __stdcall
PrintError (
CHAR *lpszRoutine,
CHAR *lpszCallName,
DWORD dwError
)
{
fprintf ( stderr,
"The Call to %s() in the Routine %s() failed with Error %d/n",
lpszCallName,
lpszRoutine,
dwError
);

DoCleanup ( );
exit ( 1 );
}

//
// Print an IPX address.
//
void __stdcall
PrintIpxAddress(
CHAR *lpsNetnum,
CHAR *lpsNodenum
)
{
INT i;

for ( i = 0; i < 4; i++ )
{
fprintf ( stdout, "%02X", (UCHAR) lpsNetnum );
}

fprintf ( stdout, "." );

for ( i = 0; i < 6; i++ )
{
fprintf ( stdout, "%02X", (UCHAR) lpsNodenum );
}

fprintf ( stdout, "/n" );

return;
}

//
// AtoH () coverts the IPX address specified in the string(ascii) format to
// the binary(hexadecimal) format.
//
void __stdcall
AtoH(
CHAR *szDest,
CHAR *szSource,
INT iCount
)
{
while (iCount--)
{
*szDest++ = ( BtoH ( *szSource++ ) << 4 ) + BtoH ( *szSource++ );
}
return;
}

//
// BtoH () returns the equivalent binary value for an individual
// character specified in the ascii format.
//
UCHAR __stdcall
BtoH(
CHAR ch
)
{

if ( ch >= '0' &amp;&amp; ch <= '9' )
{
return ( ch - '0' );
}

if ( ch >= 'A' &amp;&amp; ch <= 'F' )
{
return ( ch - 'A' + 0xA );
}

if (ch >= 'a' &amp;&amp; ch <= 'f' )
{
return ( ch - 'a' + 0xA );
}

//
// Illegal values in the IPX address will not be excepted
//
fprintf( stderr,
"Illegal value specified in one of the IPX Addresses-BtoH Failed/n" );

DoCleanup ( );

exit ( 1 );
}


 
谢谢 zw84611,
我先前已经完成对 TSocket 的改造,使支持 IPX 了,
现在要解决的一个附加功能是如何从一个 socket(IPX) 获取该 socket 的 IPX 地址?该
使用什么 socket API 呢,如何使用?
 
其实这些API早已有delphi版:
{******************************************************************************}
{ }
{ Winsock2 IPX API interface Unit for Object Pascal }
{ }
{ Portions created by Microsoft are Copyright (C) 1995-2001 Microsoft }
{ Corporation. All Rights Reserved. }
{ }
{ The original file is: wsipx.h, released June 2000. The original Pascal }
{ code is: WSIpx.pas, released December 2000. The initial developer of the }
{ Pascal code is Marcel van Brakel (brakelm@chello.nl). }
{ }
{ Portions created by Marcel van Brakel are Copyright (C) 1999-2001 }
{ Marcel van Brakel. All Rights Reserved. }
{ }
{ Obtained through: Joint Endeavour of Delphi Innovators (Project JEDI) }
{ }
{ You may retrieve the latest version of this file at the Project JEDI home }
{ page, located at http://delphi-jedi.org or my personal homepage located at }
{ http://members.chello.nl/m.vanbrakel2 }
{ }
{ The contents of this file are used with permission, subject to the Mozilla }
{ Public License Version 1.1 (the "License"); you may not use this file except }
{ in compliance with the License. You may obtain a copy of the License at }
{ http://www.mozilla.org/MPL/MPL-1.1.html }
{ }
{ Software distributed under the License is distributed on an "AS IS" basis, }
{ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for }
{ the specific language governing rights and limitations under the License. }
{ }
{ Alternatively, the contents of this file may be used under the terms of the }
{ GNU Lesser General Public License (the "LGPL License"), in which case the }
{ provisions of the LGPL License are applicable instead of those above. }
{ If you wish to allow use of your version of this file only under the terms }
{ of the LGPL License and not to allow others to use your version of this file }
{ under the MPL, indicate your decision by deleting the provisions above and }
{ replace them with the notice and other provisions required by the LGPL }
{ License. If you do not delete the provisions above, a recipient may use }
{ your version of this file under either the MPL or the LGPL License. }
{ }
{ For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html }
{ }
{******************************************************************************}

unit WSipx;

{$WEAKPACKAGEUNIT}

{$HPPEMIT ''}
{$HPPEMIT '#include "wsipx.h"'}
{$HPPEMIT ''}

{$I WINDEFINES.INC}

interface

//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992-1999.
//
// Windows Sockets include file for IPX/SPX. This file contains all
// standardized IPX/SPX information. Include this header file after
// winsock.h.
//
// To open an IPX socket, call socket() with an address family of
// AF_IPX, a socket type of SOCK_DGRAM, and protocol NSPROTO_IPX.
// Note that the protocol value must be specified, it cannot be 0.
// All IPX packets are sent with the packet type field of the IPX
// header set to 0.
//
// To open an SPX or SPXII socket, call socket() with an address
// family of AF_IPX, socket type of SOCK_SEQPACKET or SOCK_STREAM,
// and protocol of NSPROTO_SPX or NSPROTO_SPXII. If SOCK_SEQPACKET
// is specified, then the end of message bit is respected, and
// recv() calls are not completed until a packet is received with
// the end of message bit set. If SOCK_STREAM is specified, then
// the end of message bit is not respected, and recv() completes
// as soon as any data is received, regardless of the setting of the
// end of message bit. Send coalescing is never performed, and sends
// smaller than a single packet are always sent with the end of
// message bit set. Sends larger than a single packet are packetized
// with the end of message bit set on only the last packet of the
// send.
//

//
// This is the structure of the SOCKADDR structure for IPX and SPX.
//

type
SOCKADDR_IPX = record
sa_family: Smallint;
sa_netnum: array [0..3] of Char;
sa_nodenum: array [0..5] of Char;
sa_socket: Word;
end;
{$EXTERNALSYM SOCKADDR_IPX}
PSOCKADDR_IPX = ^SOCKADDR_IPX;
{$EXTERNALSYM PSOCKADDR_IPX}
LPSOCKADDR_IPX = ^SOCKADDR_IPX;
{$EXTERNALSYM LPSOCKADDR_IPX}
TSockAddrIPX = SOCKADDR_IPX;
PSockAddrIPX = LPSOCKADDR_IPX;

//
// Protocol families used in the "protocol" parameter of the socket() API.
//

const
NSPROTO_IPX = 1000;
{$EXTERNALSYM NSPROTO_IPX}
NSPROTO_SPX = 1256;
{$EXTERNALSYM NSPROTO_SPX}
NSPROTO_SPXII = 1257;
{$EXTERNALSYM NSPROTO_SPXII}

implementation

end.

==============================================================
socket(IPX)其实只相当于一个handle而已,地址可以从sendto()或recvfrom()中获得:
iRetVal = recvfrom ( s, pchBuffer, MAX_DATA_LEN, 0, (SOCKADDR *) psa, pcb );
其中(SOCKADDR *) psa是地址,它的数据结构(pascal):
type
SOCKADDR_IPX = record
sa_family: Smallint;
sa_netnum: array [0..3] of Char;
sa_nodenum: array [0..5] of Char;
sa_socket: Word;
end;
 
winsock1就支持IPX/SPX,不过IPX/SPX有些选项和TCP的不同
几乎所有的IPX/SPX都是基于消息的,但是大部分要连接,可
靠性都有保障。
 
服务器端程序在accept客户端连接请求时可以获取客户端的地址。
试加入以下内容(直接运行可不行),你需要调整代码以适应封装的需要。
uses wsipx;
procedure TServerWinSocket.Accept(Socket: TSocket);
var ClientAddr: SOCKADDR_IPX;
AddrStr: String;
AddrLen: Integer;
begin
AddrLen := SizeOf(ClientAddr);
ClientSocket := WinSock.accept(Socket, @ClientAddr, @AddrLen);
AddrStr := Format('客户端IPX地址:net_num:%s,node_num:%s',
[ClientAddr.sa_netnum, ClientAddr.sa_nodenum]);
end;
 
有很多朋友还没了解我现在遇到的困难和已经解决的问题:
现在已经完成对 delphi5 中 TServerSocket/TClientSocket 的改装,新的控件已经支持
IPX 协议,同时因为是改装 TServerSocket/TClientSocket ,原有的方法属性全部不变,
使用上感觉和 TServerSocket/TClientSocket 一摸一样,而她同时支持 TCP 和 IPX 协议。
现在由于很忙,没时间再整理,过段时间整理。感兴趣的朋友可以向我索取一份源码。
目前的一个小问题就是,如何从一个有效的 socket(IPX) 上获取 IPX 地址,我翻阅了部
分 socket 书,都没有这方面的讲解。自己也做了些实验:使用 gethostbyaddr 等一些函
数都不行,我的机子 IPX config 是如下:
序号 名称 网络 节点 帧
================================================================
1. IpxLoopbackAdapter 00000010 0090f510a166 [802.2]
2. 00000010 0090f510a166 [802.2]
3. NDISWANIPX 00000000 fa6120524153 [EthII]

但现在我只能获取 IpxLoopbackAdapter 地址,可想要的是 2,一定有什么方法可以的,但
现在我不知道。:(
当然以上问题只是涉及对新控件辅助功能的扩充。
 
你好qkl:
对你研究的问题我也和你有同感,
想一起研究一下,请发给我你改写的代码。
地址是:
netkstar@sina.com.cn
谢谢
 
to:qkl
我这有一个能发IPX包的控件,里面有你所需要的代码段,
获取网络号和本机网卡地址用这个函数,同时希望能得到你的
spx控件,我的 email: qlj@yeah.net 谢谢

PSockAddrIPX = ^TSockAddrIPX;
TSockAddrIPX = packed record
sa_family : short;
sa_netnum : array [0..3] of Byte;
sa_nodenum : array [0..5] of Byte;
sa_socket : u_short;
end;
var
BindAddr : TSockAddrIPX;
getsockname( FSocket, PSockAddr(@BindAddr)^, i )

for i := 0 to 3 do
FLocalNetworkNumber := BindAddr.sa_netnum;
for i := 0 to 5 do
FLocalNodeNumber := BindAddr.sa_nodenum;

 
后退
顶部