Informática
IPX (Internetwork Packet Exchange), SPX (Sequenced Packet Exchange)
Taller Numero 1
Comunicación de Datos
Indice.
1. Introducción 3
2. Apreciación global de IPX/SPX 3
2.1. La Familia de Direcciones AF_IPX 3
2.2. Familia de Identificadores de Protocolo de IPX 4
2.3. Transmisión a Red Local. 4
2.4. Transmisión a todas las rutas. 4
2.5. Transmisión Dirigida. 4
2.6. Algo sobre el Tamaño de Paquete de comunicación. 4
3. Cable coaxial 6
4. Códigos de los programas de Comunicación: 7
Funciones de Winsock 7
Código del programa en Visual Basic 12
Código del programa en C ++ Builder 14
Código del programa en Delphi 18
5. Conclusiones: 21
6. Bibliografía 21
1.Introducción sobre IPX/SPX
Este informe cubre una extensión a WinSock 2 eso es específico a la familia IPX de protocolos de transporte. También describe aspectos de WinSock bajo 2 funciones que requieren consideración especial o qué puede exhibir única conducta.
Este Protocolo proporciona servicios de transporte encima del IPX que conecta una red de computadoras capa: IPX para datagramas inestables, SPX para las tramas de mensajes fiables orientados a la conexión.
2. Apreciación global de IPX/SPX
Esta sección discute cómo usar el API Winsock 2 con la familia de protocolos IPX. Tradicionalmente, la especificación del Winsock 1.x se ha usado con la familia de protocolos IP como TCP y UDP. Sin embargo, con el advenimiento de Winsock 2, el API se ha actualizado para acceder una gama amplia de transportes y tipos de la red más fácilmente. El API Winsock 2 es suficientemente genérico que los programadores necesitan saber muy poco sobre las especificaciones de la implementación de IPX/SPX. Es obvio que las redes de IPX operan diferente que una red IP, y un poco de consideración de este hecho probablemente será evidente en los códigos.
2.1. La Familia de Direcciones AF_IPX
Las familias de direcciones IPX definen la estructura de direccionamiento para protocolos que usan direccionamiento por socket estándar IPX. Para estos transportes, una dirección endpoint consiste en un número de la red, dirección del nodo y número del socket.
El número de la red es un dominio administrativo y típicamente nombrados como solo ethernet o un segmento de token ring. El número del nodo es la dirección física de una estación. La combinación de red y nodo, forma una única dirección de la estación que se presume ser única en el mundo. Los números Red/nodo se representan en bloques ASCII o la anotación dashed como: “0101a040, 00001b498765” o “01-01-a0-40,00-00-1b-49-87-65”. La necesidad de cero Principal no está presente.
El número de socket IPX es un número de servicio de Res/transporte tal como un número de puerto TCP y no debe ser confundido con el descriptor de socket Winsock. Los números de Socket IPX son globales para la estación extremo y no pueden ligarse a las direcciones del Red/nodo específicas. Por ejemplo, si la estación extremo tiene dos tarjetas de red, un socket limite puede enviar y puede recibir en ambas tarjetas. En particular, los datagramas del socket recibirían los datagramas de la transmisión en ambas tarjetas.
Sockaddr_ipx tiene un largo de 14 bytes y es más corto que la estructura de referencia sockaddr de 16 bytes. Las aplicaciones de IPX/SPX pueden aceptar la longitud de 16 bytes así como la verdadera longitud. Si se usa el Sockaddr_ipx y una longitud codificada dura de 16 bytes, la aplicación puede asumir que tiene acceso a los dos bytes que siguen su estructura.
Valores de los campos.
sa_family Familia de Direcciones AF_IPX en el orden del host.
sa_netnum identificador de red IPX en el orden de la red.
sa_nodenum Dirección del nodo.
sa_socket número de socket IPX en el orden de la red.
2.2. Familia de Identificadores de Protocolo de IPX
El parámetro protocolar en socket() y WSASocket() es un identificador que establece un tipo de red y un método para identificar los varios protocolos de transporte que corren en la red. Distinto de IP, IPX no usa un solo valor protocolar para seleccionar una pila de transporte. No hay ningún requisito de la red para usar un valor específico para cada protocolo de transporte, uno es libre de asignarlos de una manera conveniente para las aplicaciones de Winsock. Se evitan valores entre 0 ..255 para evitar colisiones con los valores protocolares PF_INET correspondientes.
Nombre Valor Tipo Socket Descripción
Reservado | 0-255 | Reservados para los valores protocolares de PF_INET. | |
NSPROTO_IPX | 1000 - 1255 | SOCK_DGRAM SOCK_RAW | Datagrama para IPX. |
NSPROTO_SPX | 1256 | SOCK_STREAM SOCK_SEQPKT | Intercambio del paquete fiable que usa paquetes fijo-clasificados según tamaño. |
Nótese que cuando NSPROTO_SPX se especifica, el protocolo SPX II se utilizará automáticamente si ambos endpoints son capaces de hacerlo.
2.3. Transmisión a Red Local.
Una transmisión puede hacerse a la red localmente atada poniendo sa_netnum a binario 0 y sa_nodenum a binario 1. Esta transmisión puede enviarse a la red primaria para el dispositivo, o todos ataron redes localmente a la opción del proveedor de servicio. Las transmisiones a la red local no son propagadas por routers.
2.4. Transmisión a todas las rutas.
Una transmisión general a través del internet es lograda poniendo los sa_netnum y campos del sa_nodenum a binario 1. El proveedor de servicio traduce esta demanda a un “paquete del tipo 20” que las routers de IPX reconocen y remiten. Su paquete visitará todas las subredes y puede duplicarse varias veces. Los receptores deben manejar muchas copias duplicadas de su datagrama.
El uso de este tipo de la transmisión es muy impopular entre administradores de la red y su uso debe estar sumamente limitado. Muchos routers desactivan este tipo de transmisión y dejan invisible su paquete a partes de la subred.
2.5. Transmisión Dirigida.
Generalmente considerado más red-amistoso que la transmisión a todas las rutas, una transmisión dirigida limita la transmisión a la red local que usted especifica. Llene sa_netnum del número de la red designado y sa_nodenum con binario 1. Las Routers remiten esta demanda a la red del destino donde se vuelve una transmisión local. Las redes del intermedio no ven este paquete como una transmisión.
2.6. Algo sobre el Tamaño de Paquete de comunicación.
El tamaño de paquete de medios de comunicación afecta la habilidad de protocolos de IPX de transferir datos por las redes y puede nos puede desafiar a tratar con una manera de transporte independiente. IPX no segmenta paquetes, ni informa cuando se dejan caer paquetes por violaciones del tamaño. Esto significa que alguna entidad en una estación del extremo debe mantener el conocimiento del tamaño máximo de paquete a ser usado en cualquier camino de la interred. Tradicionalmente, el datagrama de IPX y los servicios orientados a la conexión SPX, han dejado esta carga a la aplicación, mientras SPXII ha usado negociación de Paquete Internet Grande para manejarlo transparentemente.
Winsock intenta poner límites racionales de tamaño de paquete para sus varios protocolos de IPX como se vera a continuación. Estos límites pueden verse y pueden ser modificados por aplicaciones vía las opciones de socket de get/set. Al determinar tamaño máximo de paquete, las tres áreas de preocupación son:
-
El tamaño de paquete de medios de comunicación
-
El tamaño paquete Routable
-
El tamaño de paquete de extremo-estación
El tamaño de paquete de medios de comunicación refleja el tamaño de paquete máximo aceptable en cualquier medio de comunicación. El tamaño del paquete varía entre medios de comunicación como ethernet y token ring. La cantidad de espacio de los datos dentro de un paquete también puede variar dentro de un medios de comunicación dados y puede depender del arreglo de título de paquete. Por ejemplo, los datos eficaces clasifican según tamaño de un paquete del ethernet varía y depende adelante si es de tipo Ethernet II, Ethernet 802.2 o Ethernet SNAP.
El tamaño paquete Routable refleja el tamaño máximo de paquete que una router puede remitir. Se construyen routers de IPX modernas para dirigir cualquier tamaño del datagrama que con tal de que permanezca dentro de la red. Sin embargo, las routers más viejas pueden limitar tamaño máximo de paquete a 576 bytes, incluyendo los títulos protocolares.
El tamaño de paquete de extremo-estación refleja el tamaño de los buffer del los extremo-estación que están en espera y han anunciado para recibir paquetes entrantes. Incluso cuando los medios de comunicación y límites de la router permiten un paquete a través de, puede ser desechado por el extremo-estación si la aplicación receptor ha anunciado un buffer más pequeño. Muchas aplicaciones de IPX/SPX tradicionales limitan tamaño del buffer de recepción tal que la porción de los datos no debe ser más grande que 512 o 1024 bytes.
3. Cable coaxial
Con respecto a las conexiones de red del tipo coaxial, la especificación IEEE 802.3 es clara:
"La MAU debe proporcionar aislamiento entre los circuitos de la capa física del DTE y el cable troncal coaxial. La impedancia de aislamiento medida entre cada conductor en los circuitos de la capa física del DTE y tanto el conductor central como el blindaje del cable coaxial debe ser mayor que 250k ohmios a 50, 60 Hz. Además la impedancia de aislamiento entre la tierra del DTE y el blindaje del cable coaxial debe ser menos de 15 ohmios entre 3 Mhz y 30 Mhz. Los medios de aislamiento deben soportar 500 Vac rms durante un minuto."
Estándar IEEE 802.3
Al contrario de otras conexiones con el equipo de usuario, tales como módems o video, la conexión Ethernet está totalmente aislada del equipo del usuario. La primera indicación de este hecho es que el espigo del conector hembra montado en el chasis está aislado del mismo por medio de un anillo plástico. En una tarjeta adaptadora para Ethernet, se dedica una sección especial aislada rodeada de áreas de espaciamiento para la interfaz coaxial. Unos aisladores especiales de alto voltaje en la tarjeta sirven de puente sobre el área de espaciamiento y permiten la comunicación entre la estación del usuario y la interfaz coaxial. Este sistema brinda excelente inmunidad ante daños relacionados con sobretensiones, excepto cuando estas sean muy grandes. Con el fin de limitar la magnitud del voltaje que puede existir entre el cable Ethernet y la estación del usuario, los adaptadores Ethernet están equipados con un supresor de sobretensiones de alto voltaje del tipo "spark gap". Para sobretensiones de más de 2000 voltios, este supresor se activará y derivará el pico hacia el chasis de la estación del usuario con el fin de evitar la ruptura del adaptador Ethernet. Desafortunadamente el pico de energía inyectado en el chasis por este supresor de sobretensiones puede hacer que otros puertos en la estación de trabajo se dañen, particularmente los puertos RS-232 que están conectados a otros equipos aterrizados tales como impresoras o plotters (los puertos conectados a equipo no aterrizado, tales como un ratón, no se dañarán). La conexión Thin Ethernet por estándar debe tener una conexión de baja impedancia a través de la barrera de aislamiento, para las altas frecuencias (ver la nota posterior). Esto se logra usando un filtro con condensador. La consecuencia desafortunada de tener este condensador es que el ruido de alta frecuencia se acopla entre el chasis del nodo de red y el cableado Ethernet. Esto permite que el ruido de tierra inter-sistema penetre a la red, lo cual puede interrumpir las comunicaciones de datos.
El estándar IEEE 802.3 especifica que cualquier segmento coaxial Ethernet que esté interconectado, debe ser aterrizado sólidamente (a tierra física) y en un solo lugar. Esta importante condición ayuda a reducir el ruido de tierra inter-sistema, aunque es llevada a la práctica muy raramente. Los administradores de la red deberían conocer la localización del punto de tierra del Ethernet y verificar que es el único punto de tierra desconectándolo periódicamente y probando la ausencia de continuidad a tierra por medio de un probador de continuidad.
4. Códigos de los programas de Comunicación:
Los programas a continuación descritos utilizan Winsock propio de cada uno de los lenguajes, y ocupando una librería de manejo del protocolo IPX.
Para la comunicación se utilizaron llamados a la API de Windows, específicamente a Winsock, la cual permite comunicar maquinas.
Se utilizaron las siguientes funciones de winsock:
WSAStartup:
La función WSAStartup inicia el uso del DLL Windows Sockets para un proceso.
int WSAStartup (
WORD wVersionRequested,
LPWSADATA lpWSAData
);
Parámetros
wVersionRequested [in] La mas reciente versión de Windows Sockets que el programa puede usar. El byte alto indica la revisión, el byte bajo indica la versión.
lpWSAData [out] Un puntero a la estructura de datos WSADATA que va a recibir los detalles de la implementación de Windows Sockets.
Socket:
La función Socket crea un socket que esta enlazado a un respectivo proveedor de servicios.
SOCKET socket (
int af,
int type,
int protocol
);
Parámetros
af [in] Una especificación de familia de direcciones.
type [in] Un tipo de especificación para el nuevo socket.
protocol [in] Un protocolo en particular para ser usado que es especifico a la familia de direcciones.
Setsockopt
La función setsockopt configura el socket.
int setsockopt (
SOCKET s,
int level,
int optname,
const char FAR * optval,
int optlen
);
Parámetros
s [in] Un descriptor que identifica al socket.
level [in] El nivel en el cual la opción es definida los niveles soportados son SOL_SOCKET y IPPROTO_TCP.
optname [in] La opción del socket la cual va a ser seteada.
optval [in] Un puntero al buffer en el cual esta el valor de la opción que se va a setear.
optlen [in] El tamaño del buffer optval.
Bind
La función Bind asocia una dirección local con un socket.
int bind (
SOCKET s,
const struct sockaddr FAR* name,
int namelen
);
Parámetros
s [in] Un descriptor identificando al socket no asociado.
name [in] La dirección para asignar el socket. La estructura sockaddr se define por los siguientes campos: sa_netnum, sa_nodenum, siipx.sa_socket, sa_family
namelen [in] El largo de name.
ioctlsocket
Esta función controla el modo del socket.
int ioctlsocket (
SOCKET s,
long cmd,
u_long FAR* argp
);
Parámetros
s [in] Un descriptor que identifica a un socket.
cmd [in] El comando a realizar en el socket s.
argp [in/out] Un puntero a un parámetro para cmd.
shutdown
Esta función desabilita enviar y/o recibir en un socket.
int shutdown (
SOCKET s,
int how
);
Parámetros
s[in] Un descriptor que identifica a un socket.
how[in] Una bandera que indica que operación va a ser desactivada.
Closesocket
Esta función cierra un socket.
int closesocket (
SOCKET s
);
Parámetros
s[in] Un descriptor que identifica a un socket.
WSACleanup
Termina el uso del windows socket DLL.
int WSACleanup (void);
sendto
Esta función envía datos a una destinación especifica.
int sendto (
SOCKET s,
const char FAR * buf,
int len,
int flags,
const struct sockaddr FAR * to,
int tolen
);
Parámetros
s[in] Un descriptor que identifica a un socket.
buf[in] Un buffer que contiene los datos a ser trasmitidos.
len[in] El largo de los datos en buf.
flags[in] Especifica el modo en que la llamada es hecha.
to[in] Un puntero opcional a la dirección del socket objetivo.
tolen[in] El tamaño de la dirección en to.
Recvfrom
Esta función recibe un datagrama y guarda la dirección que lo envio.
int recvfrom (
SOCKET s,
char FAR* buf,
int len,
int flags,
struct sockaddr FAR* from,
int FAR* fromlen
);
Parámetros
s[in] Un descriptor que identifica a un socket.
buf[out] Un buffer que contiene los datos a ser recibidos.
len[in] El largo de los datos en buf.
flags[in] Especifica el modo en que la llamada es hecha.
from[out] Un puntero opcional a una dirección con la dirección que envía.
fromlen[in/out] El tamaño de la dirección en from.
Código del programa en Visual Basic 6.0
Option Explicit
Private Sub Form_Load()
Dim RetVal As Integer
RetVal = vbIPXInitialize(Socket) 'Inicializa IPX
If RetVal = 0 Then 'Chequea si la inicialización fue exitosa. 0 = No, 1 = Si
MsgBox "IPX: Fallo la Iniciación"
End
End If
Text1.SelText = "IPX init: Exitoso" & vbCrLf
Text1.SelText = "Socket: Open Port: " & Socket & vbCrLf
Text1.SelText = "Socket: Esperando" & vbCrLf
Text1.SelText = "MaxPacketSize: " & vbIPXGetMaxPacketSize & vbCrLf & vbCrLf
Text2.MaxLength = 128 'Largo máximo del Mensaje.
End Sub
Private Sub Form_Unload(Cancel As Integer)
vbIPXShutdown
End Sub
Private Sub Text2_KeyPress(KeyAscii As Integer)
If (KeyAscii = 13) Then 'Si se Presiona enter
KeyAscii = 0
If Text2.Text = "" Then Exit Sub 'No enviar un string vacío
BroadCast (Text2.Text) 'Convertir el texto y enviarlo a todos
Text1.SelText = "LOCAL:" + Text2.Text + vbCrLf
Text2.Text = "" 'Limpiar la typebox
End If
End Sub
Private Sub Timer1_Timer()
Dim RetVal As Integer, Packet As PacketType
Dim i As Long
Dim Node As String, PacketStr As String
RetVal = vbIPXCheckForPacket(Packet) 'Existe un paquete esperando
If RetVal = 1 Then ' 1 = Si
PacketStr = GetMsg(Packet) 'Recibir el Mensaje
For i = 1 To 6
Text1.SelText = Format(Hex(Packet.Node(i)), "00") + ":"
Next i
Text1.SelText = PacketStr & vbCrLf
End If
End Sub
Modulos:
IPX2.bas
Public Const Socket As Long = &HFF
Public Sub BroadCast(Message As String)
Dim Packet As PacketType
Dim i As Long
Packet.data(0) = Len(Message) 'Se debe enviar el largo del mensaje
For i = 1 To Packet.data(0)
Packet.data(i) = Asc(Mid(Message, i, 1)) 'Convierte Chars a Ints
Next i
vbIPXBroadcastPacket Packet 'Enviar el paquete
End Sub
Public Function GetMsg(Packet As PacketType) As String
Dim PacketStr As String
For i = 1 To Packet.data(0) 'Leer todos los chars
PacketStr = PacketStr & Chr(Packet.data(i)) 'Convertir y concatenar.
Next i
GetMsg = PacketStr 'Retornar el mensaje
End Function
VBNet.bas
Type PacketType
Node(1 To 6) As Byte
data(300) As Byte
End Type
Declare Function vbIPXInitialize Lib "vbnet32" (ByVal Socket As Integer) As Integer
Declare Function vbIPXGetMaxPacketSize Lib "vbnet32" () As Integer
Declare Function vbIPXCheckForPacket Lib "vbnet32" (paket As PacketType) As Integer
Declare Sub vbIPXStartListening Lib "vbnet32" ()
Declare Sub vbIPXStopListening Lib "vbnet32" ()
Declare Sub vbIPXShutdown Lib "vbnet32" ()
Declare Sub vbIPXBroadcastPacket Lib "vbnet32" (paket As PacketType)
Declare Sub vbIPXSendPacket Lib "vbnet32" (paket As PacketType)
Código del programa en C ++ Builder 4
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
#include <Windows.h>
#include <winsock.h>
#include <wsipx.h>
#include <stdio.h>
// tamaño maximo de un paquete
#define MAILPACKETSIZE 300
// El ipx no esta inicializado
int initialized=0;
// struct IPXPacket - Esta es la estructura del paquete que vamos a enviar.
struct IPXPacket {
BYTE node[6];
BYTE data[MAILPACKETSIZE+1];
};
SOCKET sockhandle;
SOCKET Sock=0xff;
WSADATA wsadat;
unsigned oursocknum=0x8849;
SOCKADDR_IPX siipx;
TForm1 *Form1;
// showerrorbox - muestra un mensaje con el error y luego sale del proceso
void showerrorbox(char*mmm) {
MessageBox(NULL,mmm,NULL,MB_TASKMODAL | MB_OK);
ExitProcess(1);
}
// inicializa el ipx
short IPXInitialize(UINT socc) {
if (initialized) return 0; //si ya esta inicializado sale
if (WSAStartup(0x101,&wsadat)) showerrorbox("Error en inicio del Socket Windows"); //inicializa el uso del DLL para el programa
sockhandle=socket(AF_IPX,SOCK_DGRAM,NSPROTO_IPX); //crea un socket IPX para el programa
if (sockhandle==INVALID_SOCKET) showerrorbox("Error en initSocket"); //
oursocknum=socc; //
int dobroad=1; //broadcast activado
if (setsockopt(sockhandle,SOL_SOCKET,SO_BROADCAST,(char FAR*)&dobroad,sizeof(int))) //activa el broadcast
showerrorbox("Error en SetSockOpt");
//Limpia las direcciones para realizar el bind
memset(siipx.sa_netnum,0,4); //netnum=0.0.0.0
memset(siipx.sa_nodenum,0,6); //nodenum=00.00.00.00.00.00
siipx.sa_socket=oursocknum; //socket=socc
siipx.sa_family=AF_IPX; //familia=AF_IPX
WSASetLastError(0);
//Enlaza el socket de windows a nuestro socket ipx
if (bind(sockhandle,(LPSOCKADDR)&siipx,sizeof(SOCKADDR))) { //enlaza sockhandle a la direccion de siipx
closesocket(sockhandle); //cierra el socket si hay un error
WSACleanup(); //limpia Windows socket
showerrorbox("Error en bindSocket"); }
u_long nonblockingmode=1; //nonblocking activado
//Inicializa el socket para I/O
if (ioctlsocket(sockhandle,FIONBIO,&nonblockingmode)) //setea el nonblocking en nuestro socket
showerrorbox("Error en ioctlsocket");
initialized=1;
return 1;
}
// vbIPXShutdown - cierra el socket y termina el socket de windows
void IPXShutdown() {
if (initialized==0) return;
if (shutdown(sockhandle,2)) showerrorbox("Error en socket Shutdown"); //desactiva el envio en el socket
if (closesocket(sockhandle)) showerrorbox("Error en closesocket"); //cierra el socket
WSACleanup(); //termina el uso del
DLL Windows socket
initialized=0;
}
// BroadcastPacket - manda un paquete a todo computador en el mismo segmento de red
void IPXBroadcastPacket(IPXPacket*ipxpak) {
siipx.sa_family=AF_IPX; //familia=AF_IPX
memset(siipx.sa_netnum,0x0,4); //netnum=0.0.0.0
memset(siipx.sa_nodenum,0xff,6); //nodenum=FF.FF.FF.FF.FF.FF(broadcast)
siipx.sa_socket=oursocknum; //socket=oursocknum
if (sendto(sockhandle,(char FAR*)&ipxpak->data[0],MAILPACKETSIZE-1,0,(sockaddr FAR*)&siipx,14)==SOCKET_ERROR) //envia el paquete
showerrorbox("Error en Broadcast");
}
// CheckForPacket - revisa si existe un paquete y si existe lo copia dentro de el registro
short IPXCheckForPacket(IPXPacket*ipxpak) {
int sizz=14; //tamaño del
paquete = 14
memset(siipx.sa_nodenum,0xff,6); //nodenum=FF.FF.FF.FF.FF.FF(broadcast)
siipx.sa_family=AF_IPX; //familia=AF_IPX
siipx.sa_socket=oursocknum; //socket=oursocknum
if (recvfrom(sockhandle,(char FAR*)&ipxpak->data[0],MAILPACKETSIZE,0,(LPSOCKADDR)&siipx,&sizz)==SOCKET_ERROR) { //recive el paquete si
existe
if (WSAGetLastError()!=WSAEWOULDBLOCK) { char buu[30];
sprintf(buu,"recv error: %d",WSAGetLastError()); showerrorbox(buu); }
return 0; }
memcpy(ipxpak->node,siipx.sa_nodenum,6); //copia la dirección
de donde se recibio
return 1;
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormActivate(TObject *Sender)
{ Memo1->Clear();
Memo1->Lines->Add("IPX init: Success");
Memo1->Lines->Add("Socket: Open Port: 255");
Memo1->Lines->Add("Socket: Listening");
Memo1->Lines->Add("MaxPacketSize: 300");
IPXInitialize(Sock);}
//---------------------------------------------------------------------------
void __fastcall TForm1::Edit1KeyPress(TObject *Sender, char &Key)
{ IPXPacket pak;
int largo,i;
if(Key==13)
{ Key=0;
largo=Edit1->Text.Length();
pak.data[0]=largo;
for (i=1;i<=largo;i++)pak.data[i]=Edit1->Text[i];
IPXBroadcastPacket(&pak);
Edit1->Text="";
};
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{ IPXPacket pak;
int i;
AnsiString node;
AnsiString msg;
if (IPXCheckForPacket(&pak))
{
Memo1->Text=Memo1->Text+"\r\n";
for (i=0;i<6;i++)
node=node+IntToHex(int(pak.node[i]),2)+":";
for (i=1;i<=pak.data[0];i++)
msg=msg+char(pak.data[i]);
Memo1->Lines->Add(node+msg);
}
}
Código del programa en Delphi 5
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
winsock, StdCtrls, IPXUnit, ExtCtrls;
const
// tamaño maximo de un paquete
Mailpacketsize=300;
// IPXPacket - Esta es la estructura del paquete que vamos a enviar.
type
ipxpacket=record
node : array[0..6] of byte;
data : array[0..300] of byte;
end ;
TSockAddrIPX = record
sa_family : short;
sa_netnum : array [0..3] of Byte;
sa_nodenum : array [0..5] of Byte;
sa_socket : u_short;
end;
TForm1 = class(TForm)
Edit1: TEdit;
Memo1: TMemo;
Timer1: TTimer;
GroupBox1: TGroupBox;
procedure FormActivate(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure Edit1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
private
{ Private declarations }
public
{ Public declarations }
initialized:boolean;
sockhandle:tsocket;
sock:tsocket;
oursocknum:tsocket;
wsadat :TWSAdata;
siipx:TsockAddrIPX;
end;
var
Form1: TForm1;
initialized:boolean;
sockhandle:tsocket;
sock:tsocket;
oursocknum:tsocket;
wsadat :TWSAdata;
siipx:PsockAddrIPX;
ipxpak:ipxpacket;
implementation
{$R *.DFM}
// showerrorbox - muestra un mensaje con el error y luego sale del proceso
procedure showerrorbox(s:string);
begin
Application.MessageBox(pchar(s),('Error'),MB_OK);
ExitProcess(1);
end;
procedure TForm1.FormActivate(Sender: TObject);
var
i:integer;
nonblockingmode:u_long;
begin
Memo1.clear;
Memo1.lines.add('IPX init: Exitoso');
Memo1.lines.add('Socket: Open Port: 255');
Memo1.lines.add('Socket: Listening');
Memo1.lines.add('MaxPacketSize: 300');
Memo1.lines.add('');
Edit1.text:='';
// inicializa el ipx
Sock:=$ff;
oursocknum:=$8849;
if (WSAStartup($101,wsadat)=SOCKET_ERROR) then
showerrorbox('Windows Sockets startup failed');
sockhandle:=socket(AF_IPX,SOCK_DGRAM,NSPROTO_IPX);
if (sockhandle=INVALID_SOCKET) then showerrorbox('initSocket failed');
oursocknum:=sock;
i:=1;
if (setsockopt(sockhandle,SOL_SOCKET,SO_BROADCAST,@i,sizeof(integer))=SOCKET_ERROR) then
showerrorbox('SetSockOpt failed');
for i := 0 to 3 do
siipx.sa_netnum[i] := $0;
for i := 0 to 5 do
siipx.sa_nodenum[i] := $0;
siipx.sa_socket:=oursocknum;
siipx.sa_family:=AF_IPX;
WSASetLastError(0);
// bind the Windows socket to our IPX socket
if (bind(sockhandle,PSockAddr(@siipx)^,sizeof(TSockAddrIPX))=SOCKET_ERROR) then
begin
closesocket(sockhandle);
WSACleanup();
showerrorbox('bindSocket failed');
end;
nonblockingmode:=1;
// Initialize socket for I/O
if (ioctlsocket(sockhandle,FIONBIO, nonblockingmode)=SOCKET_ERROR)then
showerrorbox('ioctlsocket failed');
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
sizz,i:integer;
msg,node:string;
begin
sizz:=14;
if (recvfrom(sockhandle,ipxpak.data[0],MAILPACKETSIZE,0,PSockAddr(@siipx)^,sizz)=SOCKET_ERROR) then
begin
if (WSAGetLastError()<>WSAEWOULDBLOCK) then
Application.MessageBox(pchar('Recive Error'),('Error'),MB_OK);
end
else
begin
node:='';
msg:='';
for i := 0 to 5 do
begin
ipxpak.node[i]:=siipx.sa_nodenum[i];
node:=node+inttohex(siipx.sa_nodenum[i],2)+':';
end;
for i:=1 to ipxpak.data[0] do
msg:=msg+chr(ipxpak.data[i]);
memo1.lines.add(node+msg);
end
end;
procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
var
pak:ipxpacket;
i:integer;
begin
if Key=13 then
begin
pak.data[0]:=length(edit1.text);
for i:=1 to length(edit1.text) do
pak.data[i]:=ord(edit1.text[i]);
for i := 0 to 3 do
siipx.sa_netnum[i] := $ff;
for i := 0 to 5 do
siipx.sa_nodenum[i] := $ff;
if (sendto(sockhandle,pak.data[0],MAILPACKETSIZE-1,0,PSockAddr(@siipx)^,14)=SOCKET_ERROR) then
showerrorbox('Sendto (Broadcast) Failed');
edit1.text:='';
end;
end;
end.
5. Conclusiones:
Luego de elaborar este trabajo y desarrollar los programas en los distintos lenguajes nos dimos cuenta de la importancia de los protocolos de comunicación para establecer una red.
Lo más difícil fue encontrar librerías que nos permitieran trabajar en los distintos lenguajes, después de buscar encontramos una Liberia VBNET hecha en C++, que le daba las funciones de IPX a programas en Visual Basic, a partir de esta librería, que estaba bajo una licencia GNU, se pudo entender como se trabaja con los Sockets de Windows y pudimos extender la aplicación a distintos lenguajes como C++ y Delphi, utilizando la poderosa librería Winsock que es la que gobierna todas las comunicaciones de Windows, no pudimos entrar mas a fondo ya que como esta librería es un DLL de Microsoft, no se permite ni siquiera ver el código fuente de esta.
La investigación y la información sobre IPX es muy poca, por ser este un protocolo casi obsoleto y solo utilizado en redes Novell, la implementación de este protocolo en los distintos lenguajes fue mas o menos complicada, ya que el winsock esta hecho mas para TCP y no existen objetos IPX, por lo que tuvimos que entrar mas a fondo para poder realizar la comunicación.
La implementación en Visual Basic se realizo utilizando la librería VBNET32 que incorporaba objetos con soporte IPX, esta fue la más fácil ya que no se necesito ingresar en las llamadas a winsock.
En C++, tuvimos que adaptar dicha librería para que funcionara, esto lo hicimos mirando los fuentes y viendo como funcionaban los adaptamos a nuestro programa.
En Delphi tuvimos que a traducir el código C++, lo cual no fue muy fácil debido a que C++ es un lenguaje mucho más potente y con un manejo de memoria mucho mas claro que Delphi.
Lo más agradable para nosotros fue que todas las versiones del programa podían comunicarse entre sí, ya que teníamos la misma estructura de paquete y los mismos puertos, esto fue muy satisfactorio.
Existe un problema al realizar el programa en GCC, ya que para que Linux acepte el protocolo IPX es necesario recompilar el Kernel, tarea que no logramos concretar, a pesar de estar bien documentada, pero incluso en los HOWTO de Linux decía que esta era una tarea mas o menos complicada.
La implementación en Java no se pudo realizar debido a que los sockets de Java no soportan IPX, solo TCP, para llevar a cabo esto se deberían crear librerías desde cero lo cual no pudimos hacer debido a que no tenemos un amplio conocimiento de dicho lenguaje y la maquina virtual de Java.
6. Bibliografía
Ayuda de C++, Delphi
Microsoft Developer Network
Internet:
http://developer.novell.com/support/winsock/doc/wsanx-1.htm
Descargar
Enviado por: | Trax |
Idioma: | castellano |
País: | Chile |