SoloCodigo

Programación General => C/C++ => Mensaje iniciado por: captaindanieo en Domingo 2 de Diciembre de 2007, 14:08

Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Domingo 2 de Diciembre de 2007, 14:08
Buenos dias. Últimamente todo son problemas en el trabajo que estoy programando, y no acabo de salir de uno cuando me encuentro en otro todavía mas grande.

Antes de nada darle las gracias a Eternal Idol, por todas las respuestas y ayudas en los posts que he ido posteando estos dias atrás, y que sin duda me han ayudado a seguir adelante. Muchísimas gracias.


Mi programa, se distribuye en varias partes. El objetivo es implementar una capa de protocolo, y para ello, he hecho uso de las clases.

Mi clase L2cap, es la clase de mi capa que quiero implementar. Y dentro de ella, se hace uso de otra clase, que es la clase L2capChannel. Cuando dos instancias de L2cap establecen una comunicación entre ellas, crean un canal L2capChannel, y establecen una comunicación por socket.

Para los sockets he usado una clase que ya había implementada. Con lo cual hago uso de ella para dicha comunicación.


Los sockets los tengo en la clase L2cap, y cuando envío o recibo datos desde L2cap funciona sin problema aparente. (Es decir, si desde L2cap hago una llamada a sendRaw por ejemplo, se transmite el mensaje creado en sendRaw por el socket y llega a la otra entidad de mi programa).


La cosa es que yo necesito también que el L2capChannel, en algún momento determinado, como por ejemplo cuando reciba un mensaje de datos que sea una ConnectionRequest, deba enviar él otro mensaje que sea una ConnectionResponse. Y por tanto, para dicho envío, ha de hacer uso de los sockets. Por lo tanto, el canal debería de poder también enviar por el socket.


Primeramente pensé en pasarle en el constructor de L2capChannel, un puntero al socket. De manera que pudiese escribir din problemas. Sin embargo no funciona. Y no se por qué, porque revisé todo y debería de haber funcionado.

Otra alternativa que pensé fue en hacerlo mediante callbacks, que es la que actualmente tengo implementada (el constructor de L2capChannel en el caso de pasarle el puntero a socket lo tengo entre comentarios, y ahora solo uso el de callback). Sin embargo el resultado es el mismo.




Y ya no se que mas puedo hacer. He intentado hacerlo de todas las maneras posibles, pero llevo semanas atascado en dicha comunicación y no hay manera.  :(


La ejecución del programa ha de hacerse de la siguiente manera:
Primero ejecuto, y elijo la opción 1, que es el modo Servidor. De esa manera habrá alguien escuchando en el puerto.

Seguidamente, ejecuto el programa de nuevo, dejando el otro abierto, y ésta vez, elegimos la opción 2, que es el modo cliente. Ésto provocará que a la hora de crear mi nueva capa L2cap lo haga de forma diferente (como cliente).
Y después de crear mi capa, llama a la primitiva de L2cap OpenChannelReq.


Tanto en el caso del Servidor como del Cliente, he colocado un bucle infinito para que no finalice la ejecución del programa, y en dicho bucle saca un mensaje por pantalla.



OpenChannel se encarga de abrir un nuevo canal para una comunicación. Para ello busca un CID (identificador de canal) libre, y crea un nuevo L2capChannel, introduciéndolo en el vector de canales, y construyendo dicho canal mandándole mediante callback la funcion que usará el canal para enviar datos por el socket (ya que el socket está en L2cap y no en L2capChannel).



Seguidamente actualiza también el vector tabla, que es simplemente un registro de los canales que han sido creados en mi capa L2cap.

Y finalmente, se hace una llamada a ese canal creado en el vector, a su procedimiento connectChannel().

[connect channel, provocaría la elaboración de una Connection Request, la almacenaria en variables globales, pasaría dichas variables a un array de salida, crearia una string con el contenido a mandar, y la tendría que mandar por el socket]

Sin embargo, en lugar de toda esta secuencia de acciones, para testear la comunicación por el socket, en el mismo constructor del canal L2capChannel, he puesto que se llame al Wrapper a la función que escribe en el socket en L2cap. He puesto que escriba una cadena de caracteres, que resulta que es una ConnectionRequest.

La llamada al Wrapper se realiza perfectamente, ya que se muestra por pantalla que se ha entrado en dicha función.

Pero por el socket no se escribe nada. El Servidor debería de recibir la cadena por el socket, y no la recibe.

El cliente muestra que se ha creado un canal, muestra el contenido de la tabla, y dice que ha enviado por el socket una cadena, pero al Servidor no le llega.


Se que quizás sea muy extenso el código, he intentado reducirlo al máximo dejando solo lo indispensable para ver el problema de la comunicación por socket.
Muchísimas gracias por todo.

Pongo el código a continuación de cada uno de los archivos, comenzando por la clase Socket, seguida de los archivos de mi programa.

Muchas gracias.

-----------------------------|  socket.h  |--------------------

Código: Text
  1. #ifndef SOCKET_H
  2. #define SOCKET_H
  3.  
  4. #include <C:\Dev-Cpp\include\WinSock2.h>
  5. #include <string>
  6.  
  7. enum TypeSocket {BlockingSocket, NonBlockingSocket};
  8.  
  9. class Socket {
  10.     public:
  11.     
  12.       virtual ~Socket();
  13.       Socket(const Socket&);
  14.       Socket& operator=(Socket&);
  15.     
  16.       std::string ReceiveLine();
  17.       std::string ReceiveBytes();
  18.     
  19.       void   Close();
  20.     
  21.       // The parameter of SendLine is not a const reference
  22.       // because SendLine modifes the std::string passed.
  23.       void   SendLine (std::string);
  24.     
  25.       // The parameter of SendBytes is a const reference
  26.       // because SendBytes does not modify the std::string passed
  27.       // (in contrast to SendLine).
  28.       void   SendBytes(const std::string&);
  29.     
  30.     protected:
  31.       friend class SocketServer;
  32.       friend class SocketSelect;
  33.     
  34.       Socket(SOCKET s);
  35.       Socket();
  36.     
  37.     
  38.       SOCKET s_;
  39.     
  40.       int* refCounter_;
  41.     
  42.     private:
  43.       static void Start();
  44.       static void End();
  45.       static int  nofSockets_;
  46.  
  47. };
  48.  
  49.  
  50. class SocketClient : public Socket
  51. {
  52.     public:
  53.       SocketClient(const std::string& host, int port);
  54. };
  55.  
  56.  
  57.  
  58. class SocketServer : public Socket
  59. {
  60.     public:
  61.       SocketServer(int port, int connections, TypeSocket type=BlockingSocket);
  62.     
  63.       Socket* Accept();
  64. };
  65.  
  66.  
  67. // http: //msdn.microsoft .com/library/default.asp?url=/library/en-us/winsock/wsapiref_2tiq.asp
  68. class SocketSelect {
  69.   public:
  70.     SocketSelect(Socket const * const s1, Socket const * const s2=NULL, TypeSocket type=BlockingSocket);
  71.  
  72.     bool Readable(Socket const * const s);
  73.  
  74.   private:
  75.     fd_set fds_;
  76. };
  77.  
  78.  
  79. #endif
  80.  
  81.  


-----------------------------|  socket.cpp  |--------------------
Código: Text
  1. #include <SOCKET.h>
  2. #include <iostream>
  3.  
  4. using namespace std;
  5.  
  6.  
  7. int Socket::nofSockets_= 0;
  8.  
  9.  
  10. void Socket::Start()
  11. {
  12.   if (!nofSockets_)
  13.   {
  14.     WSADATA info;
  15.     if (WSAStartup(MAKEWORD(2,0), &info))
  16.     {
  17.       throw "Could not start WSA";
  18.     }
  19.   }
  20.   ++nofSockets_;
  21. }
  22.  
  23.  
  24. void Socket::End()
  25. {
  26.   WSACleanup();
  27. }
  28.  
  29.  
  30. Socket::Socket() : s_(0)
  31. {
  32.   Start();
  33.   // UDP: use SOCK_DGRAM instead of SOCK_STREAM
  34.   s_ = socket(AF_INET,SOCK_STREAM,0);
  35.  
  36.   if (s_ == INVALID_SOCKET)
  37.   {
  38.     throw "INVALID_SOCKET";
  39.   }
  40.  
  41.   refCounter_ = new int(1);
  42. }
  43.  
  44.  
  45. Socket::Socket(SOCKET s) : s_(s)
  46. {
  47.   Start();
  48.   refCounter_ = new int(1);
  49. };
  50.  
  51.  
  52. Socket::~Socket()
  53. {
  54.   if (! --(*refCounter_))
  55.   {
  56.     Close();
  57.     delete refCounter_;
  58.   }
  59.  
  60.   --nofSockets_;
  61.   if (!nofSockets_) End();
  62. }
  63.  
  64.  
  65. Socket::Socket(const Socket& o)
  66. {
  67.   refCounter_=o.refCounter_;
  68.   (*refCounter_)++;
  69.   s_         =o.s_;
  70.  
  71.   nofSockets_++;
  72. }
  73.  
  74.  
  75. Socket& Socket::operator=(Socket& o)
  76. {
  77.   (*o.refCounter_)++;
  78.  
  79.   refCounter_=o.refCounter_;
  80.   s_         =o.s_;
  81.  
  82.   nofSockets_++;
  83.  
  84.   return *this;
  85. }
  86.  
  87.  
  88. void Socket::Close()
  89. {
  90.   closesocket(s_);
  91. }
  92.  
  93.  
  94. std::string Socket::ReceiveBytes()
  95. {
  96.   std::string ret;
  97.   char buf[1024];
  98.  
  99.   while (1) {
  100.     u_long arg = 0;
  101.     if (ioctlsocket(s_, FIONREAD, &arg) != 0)
  102.     {
  103.       break;
  104.     }
  105.  
  106.     if (arg == 0)
  107.     {
  108.       break;
  109.     }
  110.     
  111.     if (arg > 1024)
  112.     {
  113.             arg = 1024;
  114.     }
  115.  
  116.     int rv = recv (s_, buf, arg, 0);
  117.  
  118.     if (rv <= 0)
  119.     {
  120.            break;
  121.     }
  122.  
  123.     std::string t;
  124.  
  125.     t.assign (buf, rv);
  126.     ret += t;
  127.   }
  128.  
  129.   return ret;
  130. }
  131.  
  132.  
  133. std::string Socket::ReceiveLine()
  134. {
  135.   std::string ret;
  136.   while (1)
  137.   {
  138.     char r;
  139.  
  140.     switch(recv(s_, &r, 1, 0))
  141.     {
  142.       case 0: // not connected anymore;
  143.               // ... but last line sent
  144.               // might not end in \n,
  145.               // so return ret anyway.
  146.         return ret;
  147.  
  148.       case -1:
  149.         return "";
  150. //      if (errno == EAGAIN) {
  151. //        return ret;
  152. //      } else {
  153. //      // not connected anymore
  154. //      return "";
  155. //      }
  156.     }
  157.  
  158.     ret += r;
  159.     if (r == '\n')  return ret;
  160.   }
  161. }
  162.  
  163.  
  164. void Socket::SendLine(std::string s)
  165. {
  166.   s += '\n';
  167.   send(s_,s.c_str(),s.length(),0);
  168. }
  169.  
  170.  
  171. void Socket::SendBytes(const std::string& s)
  172. {
  173.   send(s_,s.c_str(),s.length(),0);
  174. }
  175.  
  176.  
  177. SocketServer::SocketServer(int port, int connections, TypeSocket type)
  178. {
  179.   sockaddr_in sa;
  180.  
  181.   memset(&sa, 0, sizeof(sa));
  182.  
  183.   sa.sin_family = PF_INET;            
  184.   sa.sin_port = htons(port);          
  185.   s_ = socket(AF_INET, SOCK_STREAM, 0);
  186.   if (s_ == INVALID_SOCKET)
  187.   {
  188.     throw "INVALID_SOCKET";
  189.   }
  190.  
  191.   if(type==NonBlockingSocket)
  192.   {
  193.     u_long arg = 1;
  194.     ioctlsocket(s_, FIONBIO, &arg);
  195.   }
  196.  
  197.   /* bind the socket to the internet address */
  198.   if (bind(s_, (sockaddr *)&sa, sizeof(sockaddr_in)) == SOCKET_ERROR)
  199.   {
  200.     closesocket(s_);
  201.     throw "INVALID_SOCKET";
  202.   }
  203.   
  204.   listen(s_, connections);                              
  205. }
  206.  
  207.  
  208. Socket* SocketServer::Accept()
  209. {
  210.   SOCKET new_sock = accept(s_, 0, 0);
  211.   if (new_sock == INVALID_SOCKET)
  212.   {
  213.     int rc = WSAGetLastError();
  214.     if(rc==WSAEWOULDBLOCK)
  215.     {
  216.       return 0; // non-blocking call, no request pending
  217.     }
  218.     else
  219.     {
  220.       throw "Invalid Socket";
  221.     }
  222.   }
  223.  
  224.   Socket* r = new Socket(new_sock);
  225.   return r;
  226. }
  227.  
  228.  
  229. SocketClient::SocketClient(const std::string& host, int port) : Socket()
  230. {
  231.   std::string error;
  232.  
  233.   hostent *he;
  234.   if ((he = gethostbyname(host.c_str())) == 0)
  235.   {
  236.     error = strerror(errno);
  237.     throw error;
  238.   }
  239.  
  240.   sockaddr_in addr;
  241.   addr.sin_family = AF_INET;
  242.   addr.sin_port = htons(port);
  243.   addr.sin_addr = *((in_addr *)he->h_addr);
  244.   memset(&(addr.sin_zero), 0, 8);
  245.  
  246.   if (::connect(s_, (sockaddr *) &addr, sizeof(sockaddr)))
  247.   {
  248.     error = strerror(WSAGetLastError());
  249.     throw error;
  250.   }
  251. }
  252.  
  253.  
  254. SocketSelect::SocketSelect(Socket const * const s1, Socket const * const s2, TypeSocket type)
  255. {
  256.   FD_ZERO(&fds_);
  257.   FD_SET(const_cast<Socket*>(s1)->s_,&fds_);
  258.   if(s2)
  259.   {
  260.     FD_SET(const_cast<Socket*>(s2)->s_,&fds_);
  261.   }    
  262.  
  263.   TIMEVAL tval;
  264.   tval.tv_sec  = 0;
  265.   tval.tv_usec = 1;
  266.  
  267.   TIMEVAL *ptval;
  268.   if(type==NonBlockingSocket)
  269.   {
  270.     ptval = &tval;
  271.   }
  272.   else
  273.   {
  274.     ptval = 0;
  275.   }
  276.  
  277.   if (select (0, &fds_, (fd_set*) 0, (fd_set*) 0, ptval) == SOCKET_ERROR)
  278.     throw "Error in select";
  279. }
  280.  
  281. bool SocketSelect::Readable(Socket const* const s)
  282. {
  283.   if (FD_ISSET(s->s_,&fds_)) return true;
  284.   return false;
  285. }
  286.  
  287.  


-----------------------------|  tipos.h  |--------------------
Código: Text
  1. //                              DEFINICION DE TIPOS
  2.  
  3. typedef unsigned int Tpdu_L2CAP [1200]; // Dato de entrada, PDU L2CAP  
  4.  
  5.  
  6.  
  7. typedef struct {
  8.   unsigned int Code;
  9.   unsigned int ID;
  10.   int Length;
  11.   int PSM;
  12.   int SCID;
  13. } TL2CAP_con_req;    // Connection Request packet
  14.  
  15. typedef struct {
  16.   unsigned int Code;
  17.   unsigned int ID;
  18.   int Length;
  19.   int DCID;
  20.   int SCID;
  21.   int Result;
  22.   int Status;
  23. } TL2CAP_con_res;   // Connection Response packet
  24.  
  25.  

-----------------------------|  constantes.h  |--------------------
Código: Text
  1. // Codigos de los comandos de señalizacion
  2.  
  3. #define L2CAP_CONREQ 0x02
  4. #define L2CAP_CONRES 0x03
  5.  
  6.  
  7. // Estados definidos en la máquina de estados
  8.  
  9. #define CLOSED 0x00
  10. #define WAIT_CONNECT 0x01
  11. #define WAIT_CONNECT_RSP 0x02
  12. #define CONFIG 0x03   // Consta de un numero de sub estados
  13. #define OPEN 0x04
  14. #define WAIT_DISCONNECT 0x05
  15.  
  16. // Sub estados dentro del estado CONFIG
  17.  
  18. #define WAIT_CONFIG 0x06
  19. #define WAIT_SEND_CONFIG 0x07
  20. #define WAIT_CONFIG_REQ_RSP 0x08
  21. #define WAIT_CONFIG_RSP 0x09
  22. #define WAIT_CONFIG_REQ 0x10
  23.  
  24. // Eventos
  25.  
  26. #define OPENCHANNEL_REQ 0x01
  27. #define OPENCHANNEL_RSP 0x02
  28. #define CONNECTREQ 0x03
  29. #define CONNECTRSP 0x04
  30.  
  31.  


-----------------------------|  principal.cpp  |--------------------
Código: Text
  1. #include <cstdlib>
  2. #include <iostream>
  3. #include <L2cap.h>
  4. #include <windows.h>
  5.  
  6. using namespace std;
  7.  
  8.  
  9. int main()
  10. {
  11.   int msg,opcion;
  12.   std::string cadena;
  13.     msg = 0;
  14.     
  15.     do
  16.   {
  17.     system("cls");
  18.     opcion = 0;
  19.     cout <<endl<<"                *-----------------------------------------*";
  20.     cout <<endl<<"                |        B  L  U  E  T  O  O  T  H        |";
  21.     cout <<endl<<"                *-----------------------------------------*";
  22.     cout <<endl<<"                |       M E N U   L 2 C A P   v 2.1.      |";
  23.     cout <<endl<<"                *-----------------------------------------*";
  24.     cout <<endl<<"                |                                         |";
  25.     cout <<endl<<"                |  1.- Modo Servidor................. (1) |";
  26.     cout <<endl<<"                |  2.- Modo Cliente manda PDU........ (2) |";
  27.         cout <<endl<<"                |  3.- Salir......................... (3) |";
  28.     cout <<endl<<"                |                                         |";
  29.     cout <<endl<<"                *-----------------------------------------*"<<endl<<endl<<endl;
  30.     cout <<endl<<"                  >  Elija una Opcion.......... ";
  31.     scanf("%d",&opcion);
  32.  
  33.   }while (opcion < 1 || opcion > 3);
  34.  
  35.   //Lee Menu y llama funciones
  36.   switch(opcion)
  37.     {            
  38.          case 1:
  39.              {
  40.               system("cls");
  41.               L2cap micapa(1);
  42.               while (1)
  43.               {
  44.                     cout<<"Sigo aqui en modo Servidor..."<<endl;
  45.                     Sleep(4000);  
  46.                 }
  47.                 break;
  48.              }
  49.  
  50.          case 2:
  51.              {
  52.               system("cls");
  53.               L2cap micapa(2);
  54.                 
  55.                 micapa.Openchannel_req ();
  56.                 
  57.                 //micapa.sendRaw();  
  58.                 // Si utilizo sendRaw desde aquí, SI funciona la comunicación
  59.                 //por Socket de client a Serv, pero no de Serv a cliente (el canal no escribe por socket)
  60.                 
  61.                 while (1)
  62.                 {
  63.                    cout<<"Sigo aqui en modo Cliente..."<<endl;
  64.                    Sleep(4000);  
  65.                  }
  66.               system("pause");
  67.               break;
  68.              }
  69.     
  70.         case 3:
  71.             {
  72.                 system("cls");
  73.               L2cap micapa(3);                
  74.                 micapa.Salir();
  75.                 cout <<endl<<"                >  FIN DEL PROGRAMA.........."<<endl<<endl;
  76.             break;
  77.         }
  78.     }
  79.   return 0;
  80. }  
  81.  
  82.  


-----------------------------|  l2cap.h  |--------------------
Código: Text
  1. //#include <Socket.h>
  2. #include <L2capChannel.h>
  3. #include <vector>
  4. #include <string>
  5. #include <sstream>
  6. #include <iostream>
  7. #include <cstdlib>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10.  
  11. using namespace std;
  12.  
  13.  
  14.                    // DEFINICION DE TIPOS
  15.  
  16. typedef struct
  17. {
  18.     unsigned int CID;
  19.   unsigned int PSM;
  20.   int funcptr;
  21. } Ttabla;
  22.  
  23.  
  24. typedef L2capChannel *Tpcanal;
  25.  
  26.  
  27.  
  28. class L2cap
  29. {
  30.  
  31.  public:
  32.         
  33.      L2cap (int mode);  // Constructor.
  34.      ~L2cap (); // Destructor.
  35.      void Salir ();    
  36.      void Send_Data(std::string cadena); // Modo Cliente        
  37.      void Server(int argc, char* argv[]); // Modo Servidor
  38.      void leerSocketClient();
  39.      void leerSocketServer();
  40.      void leerSocket();
  41.      void sendRaw();
  42.      bool escuchando();
  43.  
  44.      void escribeEnSocket(std::string cadena);
  45.      static void Wrapper_a_escribeEnSocket (void* pt2Object, std::string cadena);
  46.  
  47.  
  48.      int Openchannel_req ();
  49.  
  50.  
  51.  private:    
  52.                        // VARIABLES GLOBALES
  53.      Socket *s;
  54.      bool _escuchando;
  55.      vector<Ttabla> tabla;
  56.      vector<L2capChannel*> canales;
  57.     
  58.       
  59.                          //     FUNCIONES
  60.  
  61.         void string_to_bytearray (std::string str, unsigned int* &array, int& size);
  62.  
  63.         unsigned int Leertipotrama (Tpdu_L2CAP datain);
  64.         static unsigned __stdcall bucleLectura(void* a);
  65.         void Analiza_contenido(std::string r);
  66.         int BuscaTabla(int cid);
  67.         void ImprimeTabla();
  68.         int AsignaCID(void);
  69. };
  70.  
  71.  


-----------------------------|  l2cap.cpp  |--------------------
Código: Text
  1. #include <L2cap.h>
  2. #include <Socket.h>
  3. #include <vector>
  4. #include <process.h>
  5. #include <string>
  6. #include <sstream>
  7. #include <iostream>
  8. #include <cstdlib>
  9. #include <stdio.h>
  10.  
  11. using namespace std;
  12.  
  13.  
  14. bool L2cap::escuchando()
  15. {
  16.      return _escuchando;
  17. }
  18.  
  19.  
  20. unsigned __stdcall L2cap::bucleLectura(void* a)
  21. {
  22.   L2cap *thisL2cap = (L2cap*)a;
  23.     
  24.   while (thisL2cap->escuchando())
  25.   {
  26.     cout<<endl<<"Esperando Nuevos datos..."<<endl;
  27.     thisL2cap->leerSocket();
  28.   }
  29.   return 0;
  30. }
  31.  
  32.  
  33. L2cap::L2cap (int mode)  // Constructor
  34. {
  35.    _escuchando = true;
  36.  
  37.    if (mode==1) // Modo Servidor
  38.    {
  39.    SocketServer in(3000,5);
  40.    Socket* sa=in.Accept();
  41.    s = sa;
  42.    cout<<"Conexion Recibida"<<endl;      
  43.  
  44.    unsigned ret;
  45.    _beginthreadex(0,0,bucleLectura,(void*)this,0,&ret);
  46.    }
  47.  
  48.    else if (mode==2) // Modo Cliente
  49.    {
  50.    SocketClient sb("pc.", 3000);
  51.    s = &sb;
  52.    *(s) = sb; //Con esto hemos anclado el contenido del puntero y ya no se borra al salir del Constructor
  53.  
  54.  
  55.    unsigned ret;
  56.    _beginthreadex(0,0,bucleLectura,(void*)this,0,&ret);
  57.    }
  58. } //Ctor
  59.  
  60.  
  61.  
  62. L2cap::~L2cap ()  // Destructor
  63. {
  64. }
  65.  
  66.  
  67.  
  68. void L2cap::string_to_bytearray(std::string str, unsigned int* &array, int& size)
  69. {
  70.   int length = str.length();
  71.   // nos aseguramos de que la cadena entrante tiene un número de elementos par
  72.   if(length%2 == 1)
  73.   {
  74.     str = "0" + str;
  75.     length++;
  76.   }
  77.   // Reservamos memoria para el array de salida  
  78.   array = new unsigned int[length/2];
  79.   size = length/2;
  80.  
  81.   std::stringstream sstr(str);
  82.  
  83.   for(int i=0; i < size; i++)
  84.   {
  85.     char ch1, ch2;
  86.     sstr >> ch1 >> ch2;
  87.     unsigned int dig1, dig2;
  88.     if(isdigit(ch1)) dig1 = ch1 - '0';
  89.     else if(ch1>='A' && ch1<='F') dig1 = ch1 - 'A' + 10;
  90.     else if(ch1>='a' && ch1<='f') dig1 = ch1 - 'a' + 10;
  91.     if(isdigit(ch2)) dig2 = ch2 - '0';
  92.     else if(ch2>='A' && ch2<='F') dig2 = ch2 - 'A' + 10;
  93.     else if(ch2>='a' && ch2<='f') dig2 = ch2 - 'a' + 10;
  94.     array[i] = dig1*16 + dig2;
  95.   }
  96. }
  97.  
  98.  
  99.  
  100. unsigned int L2cap::Leertipotrama(Tpdu_L2CAP datain)    
  101. {
  102.   unsigned int tipo;
  103.  
  104.   if ((*(datain+2)==0x01)&(*(datain+3)==0x00))  
  105.   {
  106.     tipo = 'C'; // Trama de control. c-frame
  107.   }
  108.   else if ((*(datain+2)==0x02)&(*(datain+3)==0x00))
  109.   {
  110.     tipo = 'G'; // Trama G. Canal no orientado a conexión
  111.   }
  112.   else if ((*(datain+2)>=0x40))
  113.   {
  114.     tipo = 'B';  // Trama-B
  115.   }
  116.   else
  117.   {
  118.     tipo = 'N'; // Tipo no válido
  119.   }
  120.   return tipo;
  121. }
  122.  
  123.  
  124. void L2cap::Salir () // Funcion que manda por socket la cadena salir que hace que salga del bucle infinito Server
  125. {
  126.    int i;
  127.   
  128.    SocketClient s("pc.", 3000); //No hace falta crear el socket de nuevo
  129.    std::string c1 = "exit";
  130.    s.SendBytes(c1);
  131. }
  132.  
  133.  
  134. int L2cap::BuscaTabla(int cid)
  135. {
  136.     int bus=-1;
  137.     for (int i=0; i<tabla.size();i++)
  138.     {
  139.         if (tabla[i].CID==cid)
  140.         {
  141.            bus=i;
  142.         }
  143.     }
  144.     return bus;
  145.     //Si no ha encontrado registrado en la tabla el CID buscado, devuelve -1,
  146.     //En caso de q lo encuentre, devuelve la posicion en la que se encuentra el
  147.     //canal con dicho CID
  148. }
  149.  
  150.  
  151. void L2cap::ImprimeTabla()
  152. {
  153.     printf("\n\n----TABLA DE REGISTRO DE CANALES L2CAP----\n");
  154.     for (int i=0; i<tabla.size();i++)
  155.     {
  156.         printf("tabla [%d].CID = %X \n",i,tabla[i].CID);
  157.         printf("tabla [%d].PSM = %X \n\n",i,tabla[i].PSM);
  158.     }
  159. }
  160.  
  161.  
  162.  
  163. int L2cap::AsignaCID()
  164. //Busca, para una trama de datos (B), que CID hay libre para asignarle
  165. //a la comunicación actual
  166. {
  167.     int nuevoCID=0x40;
  168.     while (BuscaTabla(nuevoCID)>=0)
  169.     {
  170.           printf("Ya esta registrado el CID de valor %X \n",nuevoCID);
  171.           nuevoCID++;
  172.     }
  173.     printf("Registrado con exito el CID de valor %X \n",nuevoCID);
  174.     return nuevoCID; //Devuelve el 1ero que no esta en la tabla
  175. }
  176.  
  177.  
  178. void L2cap::Analiza_contenido(std::string r)
  179. {
  180.     unsigned int longitud, tipo;
  181.      unsigned int* datain = NULL;
  182.     int size,CID,bus,num;
  183.  
  184.     size = r.length();
  185.     if (size>0)
  186.     {  
  187.       if (r =="exit")
  188.       {
  189.           _escuchando = false;
  190.           cout<<"Escuchando se ha puesto a false"<<endl;
  191.       }
  192.       else
  193.       {
  194.           cout <<"Recibida una string de longitud "<<r.length()<<endl<<"y contenido: "<<r<<endl<<endl;                
  195.           string_to_bytearray(r,datain,size);
  196.           
  197.           longitud = size-4; // se trata del campo length, mientras q size es toda.
  198.         
  199.           tipo = Leertipotrama (datain);
  200.         
  201.           switch (tipo)
  202.             {
  203.             case 'C' :  // Se trata de una trama-C
  204.               {    
  205.                 printf("Es una trama C \n \n");
  206.                      // Primero vemos de que comando se trata
  207.                            int code = *(datain+4);
  208.                           
  209.                            if (code==L2CAP_CONREQ)
  210.                            {
  211.                              //Creamos un canal nuevo, actualizamos tabla,...
  212.                            int receivedPSM = *(datain+8) + (*(datain+9))*256;
  213.                              CID = AsignaCID(); //Asignamos nuevo CID
  214.                              cout<<"Recibida Connection Request"<<endl;
  215.  
  216.                              canales.push_back(new L2capChannel(CID,receivedPSM,s)); //puntero a socket
  217.                              Ttabla elementoTabla;
  218.                              elementoTabla.CID = CID;
  219.                              elementoTabla.PSM = receivedPSM;
  220.                              tabla.push_back(elementoTabla);
  221.                              ImprimeTabla();
  222.                            }
  223.                           
  224.                            else
  225.                            //Se trata de una: ConnectionRsp, ConfigReq,
  226.                            //ConfigRsp*, DiscReq
  227.                            {
  228.                                CID = *(datain+8) + (*(datain+9))*256;
  229.                            }
  230.                         
  231.                         bus=BuscaTabla(CID);
  232.                         if (bus >=0)
  233.                         {
  234.                            num=canales[bus]->entradaComandos(datain,longitud);
  235.                         }
  236.  
  237.                     break;
  238.                     }
  239.         
  240.             case 'G' :  // Se trata de una trama-G
  241.               {
  242.                     printf("Es una trama G \n \n");    
  243.               break;
  244.               }
  245.         
  246.             case 'B' : //Se trata de una trama-B
  247.               {
  248.                         printf("Es una trama B \n \n");
  249.                   break;
  250.               }
  251.                 
  252.                 case 'N':
  253.               {
  254.               printf("Trama no valida. \n \n");
  255.                   break;
  256.               }
  257.                 
  258.                 default :
  259.               {
  260.                 printf("Algo esta pasando... \n \n");
  261.               }
  262.                }        
  263.       }      
  264.     }
  265. }
  266.  
  267.  
  268.  
  269.  
  270. void L2cap::leerSocket()
  271. {
  272.      cout<<"Voy a leer"<<endl;
  273.  
  274.      std::string r = "";
  275.      while (r.length()==0)
  276.      {
  277.        r = s->ReceiveBytes();
  278.      }
  279.      Analiza_contenido(r);    
  280.      cout<<"Ya he leido"<<endl;
  281. }
  282.  
  283.  
  284.  
  285. void L2cap::sendRaw()
  286. {
  287.     std::string cadena="080001000205040001004000"; //Connection Request    
  288.     escribeEnSocket(cadena);
  289.     cout<<"He enviado una cadena"<<endl;
  290. }
  291.  
  292.  
  293. int L2cap::Openchannel_req ()
  294. {
  295.     int res = 0;
  296.     int PSM = 2;
  297.     int CID,bus,num;
  298.  
  299.      CID = AsignaCID();
  300.     
  301. // Metemos en el vector de canales un nuevo elemento Canal que creamos con su constructor
  302.  
  303. //     canales.push_back(new L2capChannel(CID,PSM,s)); // Puntero a socket
  304.      canales.push_back(new L2capChannel(CID,PSM,(void*)this,&Wrapper_a_escribeEnSocket)); // Callback
  305.     
  306.  
  307. // Metemos tambien los datos del canal que hemos creado para registrarlo en la tabla
  308.  
  309.      Ttabla elementoTabla;
  310.      elementoTabla.CID = CID;
  311.      elementoTabla.PSM = PSM;
  312.      tabla.push_back(elementoTabla);
  313.      ImprimeTabla();        
  314.  
  315.     bus=BuscaTabla(CID);
  316.     if (bus >=0)
  317.     {
  318.        num=canales[bus]->connectChannel(); // Llamamos a connectChannel dentro de L2capChannel
  319.     }
  320.     return res;
  321. }
  322.  
  323.  
  324. void L2cap::escribeEnSocket(std::string cadena)
  325. {
  326.      cout<<"Cadenita a mandar: "<<cadena<<endl;
  327.      s->SendBytes(cadena);
  328. }
  329.  
  330.  
  331.  
  332. void L2cap::Wrapper_a_escribeEnSocket (void* pt2Object, std::string cadena)
  333. {
  334.      cout<<"Welcome to WRAPPER"<<endl;
  335.        L2cap* mySelf = (L2cap*) pt2Object;
  336.        mySelf->escribeEnSocket(cadena);
  337.       
  338.       //mySelf->sendRaw();  // Esto debería de funcionar, pero tampoco
  339. }
  340.  
  341.  


-----------------------------|  l2capChannel.h  |--------------------
Código: Text
  1. #include <iostream>
  2. #include <string>
  3. #include <tipos.h>
  4. #include <constantes.h>
  5. #include <Socket.h>
  6.  
  7.  
  8. using namespace std;
  9.  
  10. class L2capChannel
  11. {
  12.  
  13.  
  14.  public:
  15.         
  16.          L2capChannel (int CID, int PSM,Socket* a);  // Constructor. Se encarga de la correcta inicializacion
  17.          L2capChannel (int CID, int PSM,void* a, void(*pt2Func)(void*, std::string));
  18.          ~L2capChannel ();
  19.          unsigned int Obtener_estado();
  20.  
  21.          int entradaComandos (Tpdu_L2CAP pdu, unsigned int longitud);
  22.          int connectChannel();
  23.         
  24.  private:        
  25.                        // VARIABLES GLOBALES
  26.  
  27.     unsigned int _estado; // Indica el estado en el que nos encontramos
  28.     unsigned int _leidos;
  29.     unsigned int _MTU_negociada;
  30.     unsigned int _MTU_sig; // de señalizacion
  31.     unsigned int _identifier, _receivedIdentifier;
  32.     int _localCID, _remoteCID, _PSM;
  33.     void* _ME;
  34.  
  35.     Socket* sockCanal;
  36.  
  37.  
  38.                       //Variables de cada tipo de comando
  39.  
  40.   TL2CAP_con_req L2CAPcon_req_TX, L2CAPcon_req_RX;
  41.   TL2CAP_con_res L2CAPcon_res_TX, L2CAPcon_res_RX;
  42.     
  43.  
  44.                          //     FUNCIONES
  45.     
  46.     void sendComando (unsigned int tipocomando);    
  47.     void imprimeArray (Tpdu_L2CAP datain, unsigned int longitud);
  48.  
  49.     
  50.                          // funciones de lectura de cada tipo de trama-C        
  51.         void leerL2CAPcon_req(Tpdu_L2CAP pdu, unsigned int &n);
  52.         int  leerL2CAPcon_res(Tpdu_L2CAP pdu, unsigned int &n);
  53.  
  54.         void imprimeComando (unsigned int codigo);
  55.     
  56.  
  57.     void escribeL2CAPcon_req_TX (void);
  58.     void escribeL2CAPcon_res_TX (int result);
  59.  
  60.     
  61.     void situacion ();
  62.         
  63.     void vuelcaL2CAPcon_req(Tpdu_L2CAP &dataout);
  64.     void vuelcaL2CAPcon_res(Tpdu_L2CAP &dataout);
  65.     
  66.     string arrayToString(Tpdu_L2CAP a);
  67.     bool Esnumero (char valor);
  68. };
  69.  
  70.  
  71.  
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Domingo 2 de Diciembre de 2007, 14:12
-----------------------------|  l2capChannel.cpp  |--------------------
Código: Text
  1. #include <stdlib.h>
  2. #include <iostream>
  3. #include <time.h>
  4. #include <sstream>
  5. #include <string>
  6. #include <L2capChannel.h>
  7.  
  8.  
  9. using namespace std;
  10.  
  11.  
  12.  
  13. L2capChannel::L2capChannel (int CID, int PSM, Socket* a)  // Constructor
  14. {
  15.     _estado = CLOSED;
  16.     _localCID = CID;
  17.     _PSM = PSM;
  18.     sockCanal = a;
  19.  
  20.     std::string cad = "080001000305040001004000";
  21.     sockCanal->SendBytes(cad); // No escribe, no se por que
  22. }
  23.  
  24. L2capChannel::L2capChannel (int CID, int PSM,void* a, void(*pt2Func)(void*, std::string))
  25. {
  26.     _estado = CLOSED;
  27.     _localCID = CID;
  28.     _PSM = PSM;
  29.     _ME = a;
  30.     cout<<"Se supone que enviamos!"<<endl;  
  31.     pt2Func (_ME,"080001000205040001004000"); // Llama al Wrapper y éste deberia escribir, pero no lo hace
  32.  
  33. //    _ME->sendRaw(); // deberia poder mandar asi tambien, pero no
  34. }
  35.  
  36. L2capChannel::~L2capChannel ()  // Constructor
  37. {
  38. }
  39.  
  40.  
  41.  
  42. void L2capChannel::imprimeArray (Tpdu_L2CAP datain, unsigned int longitud)
  43. {
  44.      unsigned int i;
  45.  
  46.    printf(" \n\n El array de datos es el siguiente: \n \n");      
  47.      for (i=0; i<(longitud); i++)
  48.      {
  49.          printf("%X ",*(datain+i));        
  50.      }
  51.    printf(" \n \n");
  52. }
  53.  
  54.  
  55. void L2capChannel::escribeL2CAPcon_req_TX ()
  56. {
  57.     L2CAPcon_req_TX.Code = L2CAP_CONREQ;
  58.     L2CAPcon_req_TX.ID = _identifier;              
  59.     L2CAPcon_req_TX.Length = 4;
  60.     L2CAPcon_req_TX.PSM = _PSM;
  61.     L2CAPcon_req_TX.SCID = _localCID;
  62. }
  63.  
  64.  
  65. void L2capChannel::escribeL2CAPcon_res_TX (int result)
  66. {
  67.        L2CAPcon_res_TX.Code = L2CAP_CONRES;
  68.        L2CAPcon_res_TX.ID = L2CAPcon_req_RX.ID;    
  69.        L2CAPcon_res_TX.Length = 6;
  70.        L2CAPcon_res_TX.DCID = _localCID;
  71.        L2CAPcon_res_TX.SCID = _remoteCID;
  72.        L2CAPcon_res_TX.Result = result;
  73.        L2CAPcon_res_TX.Status = 0x0000;
  74. }
  75.  
  76.  
  77.  
  78.  
  79. void L2capChannel::leerL2CAPcon_req(Tpdu_L2CAP datain, unsigned int &n)
  80. {
  81.     L2CAPcon_req_RX.Code = *(datain + n);
  82.    L2CAPcon_req_RX.ID = *(datain + n+1);    
  83.   L2CAPcon_req_RX.Length = *(datain + n+2) + (*(datain+n+3))*256;
  84.   L2CAPcon_req_RX.PSM = *(datain + n+4) + (*(datain+n+5))*256;
  85.   L2CAPcon_req_RX.SCID = *(datain + n+6) + (*(datain+n+7))*256;
  86.   int _remoteCID = L2CAPcon_req_RX.SCID;
  87.    
  88.     n += (L2CAPcon_req_RX.Length + 4);
  89.     cout<<"vamos por aqui"<<endl;
  90.  
  91.  
  92.     if (_estado==CLOSED)
  93.     {
  94.        unsigned int result=0; //successfull
  95.        if (result==0)
  96.        {
  97.           escribeL2CAPcon_res_TX (result);
  98.           _estado=WAIT_CONFIG;
  99.        }
  100.        else if (result==1) //pending
  101.        {
  102.             escribeL2CAPcon_res_TX (result);
  103.             _estado=WAIT_CONNECT;
  104.        }
  105.        else //No puede
  106.        {
  107.             escribeL2CAPcon_res_TX (result);
  108.        }
  109.        sendComando(L2CAP_CONRES);
  110.     }
  111. } // leerL2CAPcon_req
  112.  
  113.  
  114. int L2capChannel::leerL2CAPcon_res(Tpdu_L2CAP datain, unsigned int &n)
  115. {
  116.     unsigned int _receivedIdentifier = *(datain + n+1);
  117.    
  118.      switch (_estado)
  119.      {
  120.       case WAIT_CONNECT_RSP:
  121.            {
  122.                 if (L2CAPcon_req_RX.ID !=_receivedIdentifier)
  123.                 {
  124.                    cout<<"Identificador no se corresponde con el esperado."<<endl;      
  125.                    return 2;
  126.                 }
  127.            
  128.                 L2CAPcon_res_RX.Code = *(datain + n);      // Code = 03
  129.               L2CAPcon_res_RX.ID = *(datain + n+1);    
  130.               L2CAPcon_res_RX.Length = *(datain + n+2) + (*(datain+n+3))*256;
  131.               L2CAPcon_res_RX.DCID = *(datain + n+4) + (*(datain+n+5))*256;
  132.               L2CAPcon_res_RX.SCID = *(datain + n+6) + (*(datain+n+7))*256;
  133.               L2CAPcon_res_RX.Result = *(datain + n+8) + (*(datain+n+9))*256;
  134.               L2CAPcon_res_RX.Status = *(datain + n+10) + (*(datain+n+11))*256;
  135.            
  136.                 n += (L2CAPcon_res_RX.Length + 4);  
  137.                        
  138.                switch (L2CAPcon_res_RX.Result)
  139.                {
  140.                       case 0: //Success
  141.                            {
  142.                             _estado = WAIT_CONFIG;
  143.                             _remoteCID = L2CAPcon_res_RX.DCID;
  144.                             break;
  145.                            }
  146.                       case 1: //pending
  147.                            {
  148.                            break;
  149.                            }
  150.                       case 2: //Refused
  151.                            {
  152.                            _estado = CLOSED;
  153.                            cout<<"PSM not supported."<<endl;
  154.                            return -1;
  155.                            break;
  156.                            }
  157.                       case 3: //Refused
  158.                            {
  159.                            _estado = CLOSED;
  160.                            cout<<"Security block."<<endl;
  161.                            return -1;
  162.                            break;
  163.                            }
  164.                       case 4: //Refused
  165.                            {
  166.                            _estado = CLOSED;
  167.                            cout<<"No resources available."<<endl;
  168.                            return -1;
  169.                            break;
  170.                            }
  171.                            
  172.                       default:
  173.                               {
  174.                               }                      
  175.                }              
  176.                return 0;
  177.                break;
  178.            }
  179.  
  180.       default :
  181.               {
  182.                return 1;
  183.               }
  184.      }
  185. }
  186.  
  187.  
  188.  
  189. void L2capChannel::imprimeComando (unsigned int codigo)
  190. {
  191.      unsigned int i;
  192.      
  193.      switch (codigo)
  194.      {
  195.      case L2CAP_CONREQ :
  196.       {
  197.         printf("\n \n*****Connection Request******* \n");                                  
  198.         printf("El campo Code es de valor %X \n",L2CAPcon_req_RX.Code);
  199.         printf("El campo ID es de valor %X \n",L2CAPcon_req_RX.ID);
  200.         printf("El campo Length es de valor %X \n",L2CAPcon_req_RX.Length);
  201.         printf("El campo PSM es de valor %X \n",L2CAPcon_req_RX.PSM);
  202.         printf("El campo SCID es de valor %X \n \n",L2CAPcon_req_RX.SCID);
  203.       break;
  204.       }
  205.      case L2CAP_CONRES :
  206.       {
  207.         printf("\n \n*****Connection Response******* \n");                                  
  208.         printf("El campo Code es de valor %X \n",L2CAPcon_res_RX.Code);
  209.         printf("El campo ID es de valor %X \n",L2CAPcon_res_RX.ID);
  210.         printf("El campo Length es de valor %X \n",L2CAPcon_res_RX.Length);
  211.         printf("El campo DCID es de valor %X \n",L2CAPcon_res_RX.DCID);
  212.         printf("El campo SCID es de valor %X \n",L2CAPcon_res_RX.SCID);
  213.         printf("El campo Result es de valor %X \n",L2CAPcon_res_RX.Result);
  214.         printf("El campo Status es de valor %X \n \n",L2CAPcon_res_RX.Status);
  215.       break;
  216.       }
  217.      }
  218. }
  219.  
  220.  
  221. int L2capChannel::entradaComandos (Tpdu_L2CAP pdu, unsigned int longitud)
  222. {
  223.     int res;
  224.     unsigned int n, tipocomando;
  225.  
  226.     // Comprobamos que realmente se ha recibido una trama de control
  227.   if (!(*(pdu+2)==0x01)&(*(pdu+3)==0x00))  
  228.   {
  229.     cout<<"Esperado trama-C. Entrada no valida."<<endl;
  230.     return 1;
  231.   }
  232.     cout<<"Efectivamente era una trama de control. Ya estamos en el CANAL."<<endl;
  233.  
  234.    
  235.     n = 4;
  236.  
  237.        _receivedIdentifier = *(pdu+5); // de momento, sin considerar varios comandos en 1 trama-C
  238.  
  239.        tipocomando = *(pdu+n);
  240.        switch (tipocomando)
  241.        {
  242.               case L2CAP_CONREQ:
  243.                    {
  244.                     leerL2CAPcon_req(pdu,n);
  245.                     break;
  246.                    }
  247.                    
  248.               case L2CAP_CONRES:
  249.                    {
  250.                     res = leerL2CAPcon_res(pdu,n);
  251.                     break;
  252.                    }
  253.               default :
  254.                       {
  255.                            cout <<"Comando no valido."<<endl;
  256.                            return 2;
  257.                            break;
  258.                       }
  259.        }    
  260.        situacion ();
  261.    return 0;
  262. }
  263.  
  264.  
  265. void L2capChannel::situacion ()
  266. // Saca por pantalla el estado en el que nos encontramos
  267. {
  268.    switch (_estado)
  269.    {
  270.    case CLOSED :
  271.         {
  272.                printf("\t \t Estado = CLOSED \n \n");
  273.                break;
  274.         }
  275.    case WAIT_CONNECT :
  276.         {
  277.                printf("\t \t Estado = WAIT_CONNECT \n \n");
  278.                break;
  279.         }
  280.    case WAIT_CONNECT_RSP :
  281.         {
  282.                printf("\t \t Estado = WAIT_CONNECT_RSP \n \n");
  283.                break;
  284.         }
  285.    case OPEN :
  286.         {
  287.                printf("\t \t Estado = OPEN \n \n");
  288.                break;
  289.         }
  290.    case WAIT_DISCONNECT :
  291.         {
  292.                printf("\t \t Estado = WAIT_DISCONNECT \n \n");
  293.                break;
  294.         }
  295.    case WAIT_CONFIG :
  296.         {
  297.                printf("\t \t Estado = WAIT_CONFIG \n \n");
  298.                break;
  299.         }
  300.    case WAIT_SEND_CONFIG :
  301.         {
  302.                printf("\t \t Estado = WAIT_SEND_CONFIG \n \n");
  303.                break;
  304.         }
  305.    case WAIT_CONFIG_REQ_RSP :
  306.         {
  307.                printf("\t \t Estado = WAIT_CONFIG_REQ_RSP \n \n");
  308.                break;
  309.         }
  310.    case WAIT_CONFIG_RSP :
  311.         {
  312.                printf("\t \t Estado = WAIT_CONFIG_RSP \n \n");
  313.                break;
  314.         }
  315.    case WAIT_CONFIG_REQ :
  316.         {
  317.                printf("\t \t Estado = WAIT_CONFIG_REQ \n \n");
  318.                break;
  319.         }
  320.    default :
  321.            {
  322.            }
  323.    }
  324. }
  325.  
  326.  
  327. string L2capChannel::arrayToString(Tpdu_L2CAP a)
  328. {
  329.     unsigned int longitud,num,cal;
  330.  
  331.     longitud = *(a) + (*(a+1))*256;
  332.    
  333.     string result = "";
  334.  
  335.     for (int i=0; i<longitud; i++)
  336.     {
  337.       num = a[i];
  338.         if (Esnumero(char((num/16)+'0')))
  339.         {
  340.           result = result + char((num/16)+'0');
  341.         }
  342.         else
  343.         {
  344.            result = result + char((num/16)+'A'-10);  
  345.         }
  346.         cal=(num-(num/16)*16);
  347.         if (Esnumero(char( cal+'0')))
  348.         {
  349.           result = result + char(cal+'0');
  350.         }
  351.         else
  352.         {
  353.            result = result + char(cal+'A'-10);  
  354.         }
  355.     }
  356.     return result;
  357. }
  358.  
  359.  
  360. bool L2capChannel::Esnumero (char valor)
  361. {
  362.      bool test;
  363.      
  364.      switch (valor)
  365.      {
  366.             case '1':
  367.             case '2':
  368.             case '3':
  369.             case '4':
  370.             case '5':
  371.             case '6':
  372.             case '7':
  373.             case '8':
  374.             case '9':
  375.             case '0':
  376.                  {
  377.                      test = true;
  378.                      break;
  379.                  }
  380.             default :
  381.                     {
  382.                           test = false;
  383.                           break;
  384.                     }
  385.      }
  386.      return test;
  387. }
  388.  
  389.  
  390.  
  391. void L2capChannel::sendComando (unsigned int tipocomando)
  392. {
  393.      string cad;
  394.      Tpdu_L2CAP dataout ={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};  
  395.  
  396.      printf("\n Se va a enviar a continuacion una PDU de contenido: \n");
  397.    switch (tipocomando)  
  398.     {                            
  399.     case L2CAP_CONREQ :    //0x02
  400.           {
  401.           vuelcaL2CAPcon_req(dataout);
  402.           imprimeArray (dataout,L2CAPcon_req_TX.Length + 8);
  403.           break;
  404.            }
  405.  
  406.     case L2CAP_CONRES :    //0x03
  407.           {
  408.           vuelcaL2CAPcon_res(dataout);
  409.           imprimeArray (dataout,L2CAPcon_res_TX.Length + 8);          
  410.           break;
  411.           }
  412.     default : {
  413.                     printf("Error. Campo Codigo incorrecto en SendComando \n");
  414.           }
  415.     }
  416.    
  417.     cad = arrayToString(dataout);
  418.         cout<<"Se va a enviar por el socket una PDU de contenido: "<<cad<<endl;
  419.  
  420. //        sockCanal->SendBytes(cad); // Canal manda mensaje por socket, si pasasemos el puntero a socket en el constructor
  421.  
  422. //    pt2Func (_ME,cad); // Llama al Wrapper y éste deberia escribir, pero no lo hace
  423.          
  424. } //SendComando
  425.  
  426.  
  427. // ********FUNCIONES DE VOLCADO DE DATOS DESDE LAS VARIABLES REGISTRO********
  428. //  ******************** AL ARRAY DE SALIDA (PDU)****************************
  429. void L2capChannel::vuelcaL2CAPcon_req(Tpdu_L2CAP &dataout)
  430. {
  431.      unsigned int longitud,ind,res,coc;
  432.      
  433.      longitud = L2CAPcon_req_TX.Length;
  434.      coc = longitud + 4;
  435.      for (ind=0;(ind<2);ind++)
  436.      {
  437.          res = coc % 256;
  438.          *(dataout+ind) = res;
  439.          coc = coc / 256;
  440.      }
  441.  
  442.      *(dataout+ind) = 0x1;     // trama de control
  443.      ind++;
  444.      *(dataout+ind) = 0x0;    
  445.      ind++;;
  446.          
  447.      *(dataout+ind) = L2CAPcon_req_TX.Code;
  448.      ind++;
  449.  
  450.      *(dataout+ind)= L2CAPcon_req_TX.ID;
  451.      ind++;
  452.  
  453.  
  454.      coc = L2CAPcon_req_TX.Length;
  455.  
  456.      for (ind=6;(ind<8);ind++)
  457.      {
  458.          res = coc % 256;
  459.          *(dataout+ind) = res;
  460.          coc = coc / 256;
  461.      }
  462.      
  463.      coc = L2CAPcon_req_TX.PSM;
  464.  
  465.      for (ind=8;(ind<10);ind++)
  466.      {
  467.          res = coc % 256;
  468.          *(dataout+ind) = res;
  469.          coc = coc / 256;
  470.      }
  471.  
  472.      coc = L2CAPcon_req_TX.SCID;
  473.  
  474.      for (ind=10;(ind<12);ind++)
  475.      {
  476.          res = coc % 256;
  477.          *(dataout+ind) = res;
  478.          coc = coc / 256;
  479.      }
  480. }
  481.  
  482.  
  483.  
  484. void L2capChannel::vuelcaL2CAPcon_res(Tpdu_L2CAP &dataout)
  485. {
  486.      unsigned int longitud,ind,res,coc;
  487.      
  488.      longitud = L2CAPcon_res_TX.Length;
  489.      coc = longitud + 4;
  490.  
  491.      for (ind=0;(ind<2);ind++)
  492.      {
  493.          res = coc % 256;
  494.          *(dataout+ind) = res;
  495.          coc = coc / 256;
  496.      }
  497.  
  498.      *(dataout+ind) = 0x1;     // trama de control
  499.      ind++;
  500.      *(dataout+ind) = 0x0;    
  501.      ind++;;
  502.      
  503.      
  504.      *(dataout+ind) = L2CAPcon_res_TX.Code;
  505.      ind++;
  506.  
  507.      *(dataout+ind)= L2CAPcon_res_TX.ID;
  508.      ind++;
  509.  
  510.  
  511.      coc = L2CAPcon_res_TX.Length;
  512.  
  513.      for (ind=6;(ind<8);ind++)
  514.      {
  515.          res = coc % 256;
  516.          *(dataout+ind) = res;
  517.          coc = coc / 256;
  518.      }
  519.  
  520.  
  521.      coc = L2CAPcon_res_TX.DCID;
  522.  
  523.      for (ind=8;(ind<10);ind++)
  524.      {
  525.          res = coc % 256;
  526.          *(dataout+ind) = res;
  527.          coc = coc / 256;
  528.      }
  529.  
  530.      
  531.      coc = L2CAPcon_res_TX.SCID;
  532.  
  533.      for (ind=10;(ind<12);ind++)
  534.      {
  535.          res = coc % 256;
  536.          *(dataout+ind) = res;
  537.          coc = coc / 256;
  538.      }
  539.  
  540.      coc = L2CAPcon_res_TX.Result;
  541.  
  542.      for (ind=12;(ind<14);ind++)
  543.      {
  544.          res = coc % 256;
  545.          *(dataout+ind) = res;
  546.          coc = coc / 256;
  547.      }
  548.  
  549.      coc = L2CAPcon_res_TX.Status;
  550.  
  551.      for (ind=14;(ind<(longitud+8));ind++)
  552.      {
  553.          res = coc % 256;
  554.          *(dataout+ind) = res;
  555.          coc = coc / 256;
  556.      }
  557. }
  558.  
  559.  
  560.  
  561. int L2capChannel::connectChannel()
  562. {
  563.  cout<<endl<<endl<<"Creando CANAL"<<endl<<endl;
  564.     if (_estado == CLOSED)
  565.     {
  566.         srand(time(NULL));
  567.         _identifier=rand();
  568.  
  569.         escribeL2CAPcon_req_TX ();
  570.         sendComando (L2CAP_CONREQ);
  571.  
  572.         _estado = WAIT_CONNECT_RSP;
  573.         return 0;
  574.     }
  575.     else
  576.     {
  577.         cout<<"Apertura canal no valida. Estado no CLOSED."<<endl;
  578.         return 1;
  579.     }
  580. }
  581.  
  582.  

 :ayuda:
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Domingo 2 de Diciembre de 2007, 14:22
Si todo eso compila cuando pueda le dare una ojeada ya que ahora no tengo nada de tiempo. Igual te recomiendo que lo depures, si decis que escribe la linea en la pantalla fijate que pasa con lo que se supone que deberia enviar por el socket. Comproba que haga el send ... y que valor devuelve claro.
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Domingo 2 de Diciembre de 2007, 15:28
Muchas gracias EternalIdol.

Sigo intentando encontrar el por qué no funciona. Estaré atento a tu respuesta cuando puedas. Muchísimas gracias.
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Lunes 3 de Diciembre de 2007, 16:43
No logro dar con el por qué  :(
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Lunes 3 de Diciembre de 2007, 21:21
Cual es EXACTAMENTE la linea desde donde se deberia mandar y la linea desde la cual se deberia recibir ese dato.

PD. ¿Que es PC.? Lo cambie por localhost asi no me tiraba una excepcion ...
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Lunes 3 de Diciembre de 2007, 22:28
pc. es el nombre de mi computadora. En ese campo debe ir el nombre del host, de quien abre la conexión.


La línea que debería provocar la escritura es, justo en el Constructor del canal L2capchannel, la que dice:

pt2Func (_ME,"080001000205040001004000");


O sea, justo cuando creamos el canal para meterlo en el vector de canales, justo cuando lo creamos, en el costructor estamos mandando datos (esto lo hice así para probar cuanto antes el tema de los sockets).

Esa línea no es la escritura en sí, sino que provoca que se llame al Wrapper definido en L2cap (y efectivamente se le llama correctamente, ya que se muestra por pantalla un mensaje de que se está en el Wrapper).

Código: Text
  1. void L2cap::Wrapper_a_escribeEnSocket (void* pt2Object, std::string cadena)
  2. {
  3.     cout<<"Welcome to WRAPPER"<<endl;
  4.       L2cap* mySelf = (L2cap*) pt2Object;
  5.       mySelf->escribeEnSocket(cadena);
  6.      
  7.      //mySelf->sendRaw();  // Esto debería de funcionar, pero tampoco
  8. }
  9.  


En escribeEnSocket es donde se realiza la escritura en sí, y se le pasa la cadena a escribir.

En ella se realiza un SendBytes, que es lo que envía por el socket.


Muchas gracias.
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Martes 4 de Diciembre de 2007, 23:18
Para el funcionamiento de los sockets tengo incluidas en el proyecto las bibliotecas de libwsock32.a y winsock2.h.

Son las únicas bibliotecas u objetos añadidos en las opciones de proyecto. Todo lo demás está en el código.

 :unsure:
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Miércoles 5 de Diciembre de 2007, 18:41
Recien hoy tuve tiempo de ponerme con esto unos minutos, efectivamente la escritura se hace aca:

Código: Text
  1.  
  2. void Socket::SendBytes(const std::string& s)
  3. {
  4.  send(s_,s.c_str(),s.length(),0);
  5. }
  6.  
  7.  

Y send devuelve el tamaño de la cadena enviada (el envio es correcto). s (la cadena) aparentemente es correcto, igual depuralo y comproba que s_ sea el socket que queres

No me dijiste donde se recibe.
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Miércoles 5 de Diciembre de 2007, 21:39
El socket es creado en la capa L2CAP que creamos cuando elegimos la opción cliente o servidor.

Cuando elegimos Servidor, hacemos un socketserver en el puerto 3000, y estamos ahi a la escucha, y además creamos un thread paralelo a la escucha siempre de lo que pueda venir por el socket.

Cuando elegimos Cliente se define un SocketClient por ese mismo puerto 3000, y se permanece a la escucha permanente en otro thread por si llegan datos por el puerto 3000.

Cuando el canal de la capa correspondiente a servidor realiza la llamada a Sendbytes y envía por el socket, el Cliente está a la escucha de llegada de datos por ese puerto 3000, y por tanto debería recibir la cadena enviada.

La recepción de los datos por el socket se realiza en bucleLectura, a la cual se le pasa un puntero y siempre llama a thisL2cap->leerSocket(), que es donde se realiza el ReceiveBytes().


El único socket que tengo definido es 's', en L2CAP. Ya que a los canales, les paso en el constructor un puntero a ese mismo socket s, y la variable sockCanal es simplemente una copia de dicho puntero.


Debería de funcionar, ¿no?  :(
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Jueves 6 de Diciembre de 2007, 00:23
Cambie ese numero, que llega perfectamente, por una cadena:

Conexion Recibida
Sigo aqui en modo Servidor...

Esperando Nuevos datos...
Voy a leer
Recibida una string de longitud 26
y contenido: Evidentemente funciona ...

Es una trama B

Ya he leido

Esperando Nuevos datos...


No se cual es tu problema ya que esa funcion solo se usa en un lugar y va bien, depura tu codigo por favor.

Este codigo en (arg) primero devuelve l valor de la cadena y despues 0:
ioctlsocket(s_, FIONREAD, &arg)


Y fijate que se come el 100% del CPU ...
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Jueves 6 de Diciembre de 2007, 11:17
Eternal Idol, pues a mi no me realiza esas acciones al ejecutarlo.

He probado a cambiar la cadena como tu dices, pero no funciona. Ni la cadena numérica ni una cadena de letras se reciben.

En la ventana del Servidor solo se muestra lo siguiente:

Conexion Recibida
Sigo aqui en modo servidor

Esperando nuevos datos
Voy a leer
Sigo aqui en modo servidor
Sigo aqui en modo servidor
Sigo aqui en modo servidor
Sigo aqui en modo servidor
Sigo aqui en modo servidor

....


El servidor no recibe nada, y debería de hacerlo, ¿no?

Muchas gracias por las molestias. ¿Podría ser del compilador? No lo creo, ¿no? Uso el dev c++. Ya es que no se que puede estar pasando. Estoy revisando las líneas de código una por una, lo que debe de ejecutarse, y en principio debería ir. No se  :(
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Jueves 6 de Diciembre de 2007, 11:24
Si dicho envío de información a través del socket lo realizamos directamente desde mi programa principal llamando a la función que escribe en el socket [situada en l2cap], dicho envío se realiza correctamente y los datos llegan a la otra entidad. Sin embargo, si quien provoca dicho envío es el canal [que intenta enviar mediante la callback], ésto no se realiza así, y debrían de obtenerse los mismos resultados.

Como bien has dicho, el funcionamiento debería de ser ese, que el Servidor mostrase: Conexion aceptada, leer datos, se ha recibido la cadena con contenido"...", y mas datos acerca de la cadena recibida.

Sin embargo lo que obtengo yo por pantalla no es eso, sino que el servidor está a la escucha del socket y no le llega nada. Se queda en Voy a leer, y no vuelve a sacar un mensaje por pantalla, por lo que no le llega ninguna cadena por el socket.


Y el envío debería realizarse inmediatamente al crear el canal, ya que en el constructor de dicho canal, he incluido que el canal envíe por el socket una cadena determinada, directamente desde el constructor. De manera que no hace falta que se realice ninguna operación sobre el canal desde L2CAP, sino que al crearlo, automáticamente debe de haber comunicación por el socket.


De hecho, el canal llama correctamente al Wrapper, con lo cual la callback está realizada de manera correcta (se muestra un mensaje por pantalla de que éste ha sido llamado), y se llama desde el Wrapper a la función que escribe en el socket. Pero los datos no llegan a la otra entidad, y deberían.
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Jueves 6 de Diciembre de 2007, 11:25
Cita de: "captaindanieo"
El servidor no recibe nada, y debería de hacerlo, ¿no?

Muchas gracias por las molestias. ¿Podría ser del compilador? No lo creo, ¿no? Uso el dev c++. Ya es que no se que puede estar pasando. Estoy revisando las líneas de código una por una, lo que debe de ejecutarse, y en principio debería ir. No se  :(
Si, la logica es que pudiera. Proba a cambiar eso de PC. por localhost como hice yo, no veo otra diferencia.

Yo estoy usando VC++ pero al final esto debe usar la API de Windows para los sockets con lo que no deberia haber ninguna diferencia en ese sentido.
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Jueves 6 de Diciembre de 2007, 11:28
Cita de: "captaindanieo"
Si dicho envío de información a través del socket lo realizamos directamente desde mi programa principal llamando a la función que escribe en el socket [situada en l2cap], dicho envío se realiza correctamente y los datos llegan a la otra entidad. Sin embargo, si quien provoca dicho envío es el canal [que intenta enviar mediante la callback], ésto no se realiza así, y debrían de obtenerse los mismos resultados.
Te estas centrando demasiado en toda tu arquitectura - te aclaro que yo la estoy obviando -, DEPURA el codigo por favor. Comproba los valores devueltos por send y ioctlsocket.
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Jueves 6 de Diciembre de 2007, 11:32
Ok Eternal Idol, voy a ello. Muchisimas gracias.
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Jueves 6 de Diciembre de 2007, 13:06
He cambiado lo de pc. por localhost, aunque el resultado sigue siento el mismo.

He insertado unas lineas dentro de la clase SOCKET, que saquen por pantalla el valor de la variable _s, para ver su valor. Lo he realizado con un cout, y realizando una pausa justo tras escribirlo, ya que al estar siempre leyendo en el socket repetidamente no sbaa tiempoa  ver si al principio de la ejecución el valor de s_ era diferente o no.

He probado a ejecutar el programa que en lugar de realizar desde el principal la llamada a OpenChannelReq, lo haga a SendRaw (que envía una cadena de caracteres directamente).

El resultado de dicha ejecución es exitoso, y hay una transferencia de información desde el cliente a el servidor.

Los valores de s_ en transmisión (sendbytes), y en recepción (receivebytes) son:

En el servidor RX = 164, y TX = 164. Siempre.

En el cliente, TX = 124, y RX la primera vez toma un valor de 124 y las siguientes toma el valor 4518412.


La verdad es que no se que valores deberían de estar tomando s_ para que la transferencia fuera exitosa. Pero en este caso, la transferencia de datos ocurre y se hace de manera correcta.


Sin embargo, cuando estamos llamando a OpenChannelReq desde el principal, en lugar de estar llamando a SendRaw no hay transferencia desde el cliente al servidor.

Los valores de s_ son:

Servidor RX = 164, TX no se llega a transmitir nada y no aparece su valor, pero supongo que será también de 164 al igual que en la ejecución anterior con SendRaw.
En el cliente TX = 64, y RX = 64 la primera vez, y 4518412 las sucesivas.


 :(

¿Como lo habeis probado para que aparezca por el Servidor los datos enviados? ¿Solo cambiaste localhost y se está llamando a OpenChannelReq desde el principal?
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Jueves 6 de Diciembre de 2007, 13:17
Cita de: "captaindanieo"
¿Como lo habeis probado para que aparezca por el Servidor los datos enviados? ¿Solo cambiaste localhost y se está llamando a OpenChannelReq desde el principal?
Yo (solo, habeis es plural) lo probe exactamente con tu codigo. Los unicos cambios fueron el PC. por localhost y la cadena (aunque eso es innecesario, solo lo hice para asegurarme). Otra cosa, que tampoco afecta, que cambie fue los includes de tus archivos que estaban como <> por "", no deberian ser buscados en otras carpetas.

Proba justo esas dos maneras (la que te funciona y la que no) al mismo tiempo para ver si usan el mismo socket ... fijate que las dos lleguen hasta el send (la funcion de la API de Windows send) y que esta devuelva como valor de retorno el tamaño de la cadena.
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Jueves 6 de Diciembre de 2007, 16:19
He modificado los includes con las "". Y he probado a ejecutar las dos maneras al mismo tiempo (es decir, 4 ventanas de ejecución de programa), pero cada uno parece ejecutarse de manera independiente.

He incluido que se imprima por pantalla el valor devuelto por send, y en el caso que funciona (ejecutando con SendRaw en principal), efectivamente send devuelve el valor de la longitud de la cadena que se va a enviar.

Sin embargo cuando hacemos la ejecución del programa haciendo OpenChannel, el valor devuelto es -1 en lugar de la longitud de la cadena que se supone que va a mandar.

He probado a compilar el código en otro ordenador, pero el resultado es el mismo.


Debe de ser un problema de los sockets, que no estén bien definidos o algo. Es que no puedo explicarmelo.  :(


pd: quise hablarte de ti, en habeis. No se por qué puse eso en lugar de has.
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Jueves 6 de Diciembre de 2007, 16:29
Cita de: "captaindanieo"
En el caso que funciona efectivamente send devuelve el valor de la longitud de la cadena que se va a enviar.

Sin embargo cuando hacemos la ejecución del programa haciendo OpenChannel, el valor devuelto es -1 en lugar de la longitud de la cadena que se supone que va a mandar.
OK, ya estamos con algo cercano al problema entonces (como decia hay que depurarlo  ;)). En la documentacion (MSDN) dice que el valor de retorno cuando se produce un error es SOCKET_ERROR (-1) y que para obtener un valor mas especifico uses WSAGetLastError.

¿Estas usando el mismo socket las dos veces? ¿Si cambias el orden de estos dos intentos de envio el resultado sigue siendo el mismo?
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Jueves 6 de Diciembre de 2007, 17:04
He llamado a dicha función justo después de imprimir por pantalla el valor devuelto por send, y se devuelve un valor de 10038.

He buscado en la documentación, y se corresponde a éste error:

WSAENOTSOCK
10038   

Socket operation on nonsocket.

An operation was attempted on something that is not a socket. Either the socket handle parameter did not reference a valid socket, or for select, a member of an fd_set was not valid.




Las ejecuciones que estoy realizando (una haciendo que el principal llame a SendRaw, y la otra que llame a OpenChannelreq), son totalmente independientes la una de la otra en los intentos que estoy realizando ahora.

Antes probé a ejecutarlas todas simultáneamente, pero solo aquella vez.


El valor devuelto por GetLastError en el caso de SendRaw es un 0, lo cual indica que todo está correcto. (como ya podiamos ver en la ejecución, ya que los datos llegaban al Servidor).


Cuando llamamos a OpenChannelReq, ésta en L2CAP realiza una serie de acciones, y crea un canal nuevo. Al crear dicho canal, en el constructor, se hace que se produzca una callback, llamando a la función Wrapper_a_escribeEnSocket, y ésta realiza un escribeEnSocket y ya se hace la escritura.

En ningún punto de mi programa vuelvo a definir un socket, por lo que creo que el socket sigue siendo el mismo que la vez anterior.

¿Puede que el error esté en la función Wrapper_a_escribeEnSocket, al estar haciendo la llamada de escribeEnSocket desde el puntero myself?

Nunca había hecho callbacks y estuve siguiendo las instrucciones de un tutorial, y el ejemplo mostrado lo hacía de esa forma.

Como no sea que al hacer ese puntero, entienda que el socket ya no es el que era ... No se puede que sea eso ¿no? Pero entonces, ¿como tendría que ser para que se refiriese al mismo socket de mi capa?
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Jueves 6 de Diciembre de 2007, 18:26
Esta claro el problema ahora, s no es correcto, voy a ver si puedo reproducirlo aunque lo dudo. Te repito que no te voy siguiendo en tu arquitectura, por eso no te respondo a muchas de las preguntas pero creo que te estar acercando al problema finalmente.
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Jueves 6 de Diciembre de 2007, 18:28
Muchas gracias por tu ayuda Eternal Idol.
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Jueves 6 de Diciembre de 2007, 18:47
De nada, a mi me sigue funcionando.

Depura (o usa alguna cadena para mostrar en pantalla) los puntos donde es crean, se cierran y se usan los sockets. De esta manera espero que puedas saber la razon por la cual no es un socket valido en ese caso (yo no puedo reproducirlo  :( ).
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Jueves 6 de Diciembre de 2007, 19:36
Pff, pero teniendo los mismos códigos ¿por qué obtenemos diferentes resultados?
 :(

He mostrado mensajes por pantalla en cada creación, envío y recepción. Pero no logro saber por qué.

Envíame si puedes los archivos o el proyecto que tienes en un rar, a captaindanieo@yahoo.es . Lo mismo hay algo que está diferente y no caemos en la cuenta. Pero el código debe de ser exactamente el mismo. No lo se...

Si funcionase dicho código me daría una alegría, pero si no lo hiciese, y funciona en tu ordenador y no en el mio ... ya no se que hacer.  :(

Muchas gracias por tu ayuda de todas formas, Eternal Idol. Un saludo.
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Jueves 6 de Diciembre de 2007, 20:59
Los unicos cambios que hice son los que te conte, diferencias pueden ser millones, desde la version al el service pack de Windows, que usas otro compilador, etc, etc.

Depura (o usa alguna cadena para mostrar en pantalla) los puntos donde es crean, se cierran y se usan los sockets. Es la unica forma de comprender el problema realmente.
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Viernes 7 de Diciembre de 2007, 00:53
Estoy intentando probar el código en otro compilador. He bajado la versión gratuita del visual c++. Microsoft Visual Studio 2008 Version 9.0.21022.8 RTM

No logro compilar ya que aparecen un montón de errores, y me imagino que será debido a que no están incluidas algunas librerias en el proyecto.

Código: Text
  1. 1&#62;------ Build started: Project: ProyectoFC, Configuration: Debug Win32 ------
  2. 1&#62;Compiling...
  3. 1&#62;SOCKET.cpp
  4. 1&#62;C:&#092;Dev-Cpp&#092;include&#092;WinSock2.h(53) : error C2011: 'fd_set' : 'struct' type redefinition
  5. 1&#62;        C:&#092;Archivos de programa&#092;Microsoft SDKs&#092;Windows&#092;v6.0A&#092;include&#092;winsock.h(68) : see declaration of 'fd_set'
  6. 1&#62;C:&#092;Dev-Cpp&#092;include&#092;WinSock2.h(101) : error C2011: 'timeval' : 'struct' type redefinition
  7. 1&#62;        C:&#092;Archivos de programa&#092;Microsoft SDKs&#092;Windows&#092;v6.0A&#092;include&#092;winsock.h(111) : see declaration of 'timeval'
  8. 1&#62;C:&#092;Dev-Cpp&#092;include&#092;WinSock2.h(109) : warning C4005: 'timercmp' : macro redefinition
  9. 1&#62;        C:&#092;Archivos de programa&#092;Microsoft SDKs&#092;Windows&#092;v6.0A&#092;include&#092;winsock.h(124) : see previous definition of 'timercmp'
  10. 1&#62;C:&#092;Dev-Cpp&#092;include&#092;WinSock2.h(112) : error C2011: 'hostent' : 'struct' type redefinition
  11. 1&#62;        C:&#092;Archivos de programa&#092;Microsoft SDKs&#092;Windows&#092;v6.0A&#092;include&#092;winsock.h(167) : see declaration of 'hostent'
  12. 1&#62;C:&#092;Dev-Cpp&#092;include&#092;WinSock2.h(120) : error C2011: 'linger' : 'struct' type redefinition
  13. 1&#62;        C:&#092;Archivos de programa&#092;Microsoft SDKs&#092;Windows&#092;v6.0A&#092;include&#092;winsock.h(531) : see declaration of 'linger'
  14. 1&#62;C:&#092;Dev-Cpp&#092;include&#092;WinSock2.h(147) : error C2011: 'netent' : 'struct' type redefinition
  15. .....
  16.  


La cuestión es, como se pueden añadir dichas librerias. Por ejemplo, winsock2.h y libwsock32.a. Ambas las tenia importadas en las opciones de proyecto en dev c++, pero en vc++ en las opciones de proyecto y el resto de menus no encuentro nada de eso. Y he consultado la ayuda, pero no encuentro la forma.

¿Como se añaden dichos archivos al proyecto, en el visual c++?

En fin, a ver si fuera cosa del compilador.

Un saludo.
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Viernes 7 de Diciembre de 2007, 08:13
Lo contrario en este caso, tenes winsock.h y winsock2.h, deja solo la ultima. Por supuesto en el codigo que tengo yo esta #include <winsock2.h>, en cuanto al la biblioteca de importacion yo estoy usando ws2_32.lib y la tenes que agregar en las propiedades del proyecto, algo asi como enlazador, librerias adicionales. (Yo lo compile desde linea de comandos con el VC++ 8 - VS 2005 -).
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Viernes 7 de Diciembre de 2007, 12:30
No hay manera, se resiste la compilación con el vc++.

He creado otro nuevo proyecto desde cero. Un proyecto vacío. Y he añadido al proyecto los archivos de mi código.
He sustituido los <> en los includes por "". Y en uno de los archivos de socket, había un include que ponía un path entero para incluir el winsock2.h. Lo he quitado también.

En Project, en Properties, me voy a Configuration Properties, a Linker y a General. Y ahi una de las líneas que aparece es "Additional Library Directories". Ahi puedo indicarle el directorio donde se encuentran tanto winsock2 como ws2_32.lib, pero no estoy seguro de que las esté teniendo en cuenta, porque no le estoy indicando el archivo en sí.

No hay ningún otro sitio en el que pueda añadir librerias y archivos. En el devC++, en las opciones del proyecto, había un apartado que era Parámetros, Linker, y añadir libreria u objeto.

Pero aqui nada de nada.

La lista de errores que obtengo al compilar es:

Código: Text
  1. [SIZE=1]1&#62;------ Build started: Project: ProyectoVC, Configuration: Debug Win32 ------
  2. 1&#62;Linking...
  3. 1&#62;L2cap.obj : error LNK2001: unresolved external symbol __RTC_Shutdown
  4. 1&#62;L2capChannel.obj : error LNK2001: unresolved external symbol __RTC_Shutdown
  5. 1&#62;principal.obj : error LNK2001: unresolved external symbol __RTC_Shutdown
  6. 1&#62;SOCKET.obj : error LNK2019: unresolved external symbol __RTC_Shutdown referenced in function &#34;private: static void __cdecl Socket::Start(void)&#34; (?Start@Socket@@CAXXZ)
  7. 1&#62;L2cap.obj : error LNK2001: unresolved external symbol __RTC_InitBase
  8. 1&#62;L2capChannel.obj : error LNK2019: unresolved external symbol __RTC_InitBase referenced in function &#34;public: __thiscall L2capChannel::L2capChannel(int,int,class Socket *)&#34; (??0L2capChannel@@QAE@HHPAVSocket@@@Z)
  9. 1&#62;principal.obj : error LNK2001: unresolved external symbol __RTC_InitBase
  10. 1&#62;SOCKET.obj : error LNK2001: unresolved external symbol __RTC_InitBase
  11. 1&#62;L2cap.obj : error LNK2019: unresolved external symbol __RTC_CheckEsp referenced in function &#34;unsigned int __stdcall bucleLectura(void *)&#34; (?bucleLectura@@YGIPAX@Z)
  12. 1&#62;L2capChannel.obj : error LNK2001: unresolved external symbol __RTC_CheckEsp
  13. 1&#62;principal.obj : error LNK2001: unresolved external symbol __RTC_CheckEsp
  14. 1&#62;SOCKET.obj : error LNK2001: unresolved external symbol __RTC_CheckEsp
  15. 1&#62;L2cap.obj : error LNK2019: unresolved external symbol &#34;__declspec(dllimport) public: __thiscall std::basic_string&#60;char,struct std::char_traits&#60;char&#62;,class std::allocator&#60;char&#62; &#62;::basic_string&#60;char,struct std::char_traits&#60;char&#62;,class std::allocator&#60;char&#62; &#62;(char const *)&#34; (__imp_??0?&#036;basic_string@DU?&#036;char_traits@D@std@@V?&#036;allocator@D@2@@std@@QAE@PBD@Z) referenced in function &#34;public: __thiscall L2cap::L2cap(int)&#34; (??0L2cap@@QAE@H@Z)
  16. 1&#62;L2capChannel.obj : error LNK2001: unresolved external symbol &#34;__declspec(dllimport) public: __thiscall std::basic_string&#60;char,struct std::char_traits&#60;char&#62;,class std::allocator&#60;char&#62; &#62;::basic_string&#60;char,struct std::char_traits&#60;char&#62;,class std::allocator&#60;char&#62; &#62;(char const *)&#34; (__imp_??0?&#036;basic_string@DU?&#036;char_traits@D@std@@V?&#036;allocator@D@2@@std@@QAE@PBD@Z)
  17. 1&#62;SOCKET.obj : error LNK2001: unresolved external symbol &#34;__declspec(dllimport) public: __thiscall std::basic_string&#60;char,struct std::char_traits&#60;char&#62;,class std::allocator&#60;char&#62; &#62;::basic_string&#60;char,struct std::char_traits&#60;char&#62;,class std::allocator&#60;char&#62; &#62;(char const *)&#34; (__imp_??0?&#036;basic_string@DU?&#036;char_traits@D@std@@V?&#036;allocator@D@2@@std@@QAE@PBD@Z)
  18. .........
  19.  
  20. 1&#62;ProyectoVC - 83 error(s), 0 warning(s)
  21. ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========[/SIZE]
  22.  
  23.  


Edito. Acabo de encontrar otro menu, en herramientas, opciones, projects and solutions, vc++ directories. Y ahi se pueden especificar directorios para librery files, include files, ...

He añadido en library files el directorio donde se encuentra ws_32.lib y en include files el de winsock.h

Y los errores se reducen bastante aunque sigue habiendo:

Código: Text
  1. [SIZE=1]1&#62;------ Build started: Project: ProyectoVC, Configuration: Debug Win32 ------
  2. 1&#62;Linking...
  3. 1&#62;SOCKET.obj : error LNK2019: unresolved external symbol __imp__WSAStartup@8 referenced in function &#34;private: static void __cdecl Socket::Start(void)&#34; (?Start@Socket@@CAXXZ)
  4. 1&#62;SOCKET.obj : error LNK2019: unresolved external symbol __imp__WSACleanup@0 referenced in function &#34;private: static void __cdecl Socket::End(void)&#34; (?End@Socket@@CAXXZ)
  5. 1&#62;SOCKET.obj : error LNK2019: unresolved external symbol __imp__socket@12 referenced in function &#34;protected: __thiscall Socket::Socket(void)&#34; (??0Socket@@IAE@XZ)
  6. 1&#62;SOCKET.obj : error LNK2019: unresolved external symbol __imp__closesocket@4 referenced in function &#34;public: void __thiscall Socket::Close(void)&#34; (?Close@Socket@@QAEXXZ)
  7. 1&#62;SOCKET.obj : error LNK2019: unresolved external symbol __imp__recv@16 referenced in function &#34;public: class std::basic_string&#60;char,struct std::char_traits&#60;char&#62;,class std::allocator&#60;char&#62; &#62; __thiscall Socket::ReceiveBytes(void)&#34; (?ReceiveBytes@Socket@@QAE?AV?&#036;basic_string@DU?&#036;char_traits@D@std@@V?&#036;allocator@D@2@@std@@XZ)
  8. 1&#62;SOCKET.obj : error LNK2019: unresolved external symbol __imp__ioctlsocket@12 referenced in function &#34;public: class std::basic_string&#60;char,struct std::char_traits&#60;char&#62;,class std::allocator&#60;char&#62; &#62; __thiscall Socket::ReceiveBytes(void)&#34; (?ReceiveBytes@Socket@@QAE?AV?&#036;basic_string@DU?&#036;char_traits@D@std@@V?&#036;allocator@D@2@@std@@XZ)
  9. 1&#62;SOCKET.obj : error LNK2019: unresolved external symbol __imp__send@16 referenced in function &#34;public: void __thiscall Socket::SendLine(class std::basic_string&#60;char,struct std::char_traits&#60;char&#62;,class std::allocator&#60;char&#62; &#62;)&#34; (?SendLine@Socket@@QAEXV?&#036;basic_string@DU?&#036;char_traits@D@std@@V?&#036;allocator@D@2@@std@@@Z)
  10. 1&#62;SOCKET.obj : error LNK2019: unresolved external symbol __imp__WSAGetLastError@0 referenced in function &#34;public: void __thiscall Socket::SendBytes(class std::basic_string&#60;char,struct std::char_traits&#60;char&#62;,class std::allocator&#60;char&#62; &#62; const &)&#34; (?SendBytes@Socket@@QAEXABV?&#036;basic_string@DU?&#036;char_traits@D@std@@V?&#036;allocator@D@2@@std@@@Z)
  11. 1&#62;SOCKET.obj : error LNK2019: unresolved external symbol __imp__listen@8 referenced in function &#34;public: __thiscall SocketServer::SocketServer(int,int,enum TypeSocket)&#34; (??0SocketServer@@QAE@HHW4TypeSocket@@@Z)
  12. 1&#62;SOCKET.obj : error LNK2019: unresolved external symbol __imp__bind@12 referenced in function &#34;public: __thiscall SocketServer::SocketServer(int,int,enum TypeSocket)&#34; (??0SocketServer@@QAE@HHW4TypeSocket@@@Z)
  13. 1&#62;SOCKET.obj : error LNK2019: unresolved external symbol __imp__htons@4 referenced in function &#34;public: __thiscall SocketServer::SocketServer(int,int,enum TypeSocket)&#34; (??0SocketServer@@QAE@HHW4TypeSocket@@@Z)
  14. 1&#62;SOCKET.obj : error LNK2019: unresolved external symbol __imp__accept@12 referenced in function &#34;public: class Socket * __thiscall SocketServer::Accept(void)&#34; (?Accept@SocketServer@@QAEPAVSocket@@XZ)
  15. 1&#62;SOCKET.obj : error LNK2019: unresolved external symbol __imp__connect@12 referenced in function &#34;public: __thiscall SocketClient::SocketClient(class std::basic_string&#60;char,struct std::char_traits&#60;char&#62;,class std::allocator&#60;char&#62; &#62; const &,int)&#34; (??0SocketClient@@QAE@ABV?&#036;basic_string@DU?&#036;char_traits@D@std@@V?&#036;allocator@D@2@@std@@H@Z)
  16. 1&#62;SOCKET.obj : error LNK2019: unresolved external symbol __imp__gethostbyname@4 referenced in function &#34;public: __thiscall SocketClient::SocketClient(class std::basic_string&#60;char,struct std::char_traits&#60;char&#62;,class std::allocator&#60;char&#62; &#62; const &,int)&#34; (??0SocketClient@@QAE@ABV?&#036;basic_string@DU?&#036;char_traits@D@std@@V?&#036;allocator@D@2@@std@@H@Z)
  17. 1&#62;SOCKET.obj : error LNK2019: unresolved external symbol __imp__select@20 referenced in function &#34;public: __thiscall SocketSelect::SocketSelect(class Socket const * const,class Socket const * const,enum TypeSocket)&#34; (??0SocketSelect@@QAE@QBVSocket@@0W4TypeSocket@@@Z)
  18. 1&#62;SOCKET.obj : error LNK2019: unresolved external symbol ___WSAFDIsSet@8 referenced in function &#34;public: bool __thiscall SocketSelect::Readable(class Socket const * const)&#34; (?Readable@SocketSelect@@QAE_NQBVSocket@@@Z)
  19. 1&#62;C:&#092;Documents and Settings&#092;Dani&#092;Mis documentos&#092;Visual Studio 2008&#092;Projects&#092;ProyectoVC&#092;Debug&#092;ProyectoVC.exe : fatal error LNK1120: 16 unresolved externals
  20. 1&#62;Build log was saved at &#34;file://c:&#092;Documents and Settings&#092;Dani&#092;Mis documentos&#092;Visual Studio 2008&#092;Projects&#092;ProyectoVC&#092;ProyectoVC&#092;Debug&#092;BuildLog.htm&#34;
  21. 1&#62;ProyectoVC - 17 error(s), 0 warning(s)
  22. ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========[/SIZE]
  23.  
  24.  
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Viernes 7 de Diciembre de 2007, 13:08
Tenes que usar winsock2.h:
#include <winsock2.h> en lugar del path del Dev-Cpp.

Para que enlace tenes que ir al proyecto, click derecho en Propertiesy:

Configuration Properties>>Linker>>Input>>Additional Dependencies y agregar ws2_32.lib nada mas.
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Viernes 7 de Diciembre de 2007, 13:25
Compilación lograda.

Pero el resultado es el mismo. Se devuelve un -1 en getError.

E incluso diria que el resultado es peor que con dev C++, ya que cuando intento hacer una ejecución eligiendo SendRaw en el principal, también devuelve un -1. No se transmite por el socket en ninguno de los dos casos. Mientras que en devC++ sí se transmitia en éste último caso.

Edito: el error en concreto es el mismo que anteriormente, el 10038.
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Viernes 7 de Diciembre de 2007, 13:30
-1 no es nada mas que un error generico, fijate cual es el error concreto (WSAGetLastError).

Si es el mismo error que antes:
Depura (o usa alguna cadena para mostrar en pantalla) los puntos donde es crean, se cierran y se usan los sockets. Es la unica forma de comprender el problema realmente.
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Lunes 10 de Diciembre de 2007, 22:18
Creo que he encontrado el error.

En la función Wrapper_a_EscribeEnSocket, estaba llamando a Escribe en Socket, que realizaba un SendBytes, pero en realidad no estaba realizado correctamente.

El código de dicha función, a la que llamaba el canal mediante la callback, era:

Código: Text
  1. void L2cap::Wrapper_a_escribeEnSocket (void* pt2Object, std::string cadena)
  2. {
  3.     cout&#60;&#60;&#34;Welcome to WRAPPER&#34;&#60;&#60;endl;
  4.       L2cap* mySelf = (L2cap*) pt2Object;
  5.       mySelf-&#62;escribeEnSocket(cadena);
  6. }
  7.  

Lo que ocurre es que mySelf no es mi capa L2CAP. mySelf es un objeto L2CAP, y por tanto tiene los mismos métodos y por eso no da error de compilación. Pero en realidad, ni he definido el comportamiento de dicha clase L2CAP que he creado (debería decirle si es Server o Client, en su constructor), ni es lo que esperaba realizar.

Yo lo que debería es hacer referencia a mi misma clase L2CAP ya creada. Esto me imagino que será usando el puntero this, aunque no tengo ni idea de como hacerlo. ¿Como sería? La idea del código está todo correcto, salvo el tema de que no estoy llamando a EscribeEnSocket de mi clase ya creada (y por tanto, el socket definido ya conocido), sino que estaba llamando a una clase L2CAP, y estaría usando otro socket seguramente.


El canal, se creaba de la siguiente manera:

Código: Text
  1. int L2cap::Openchannel_req ()
  2. {
  3. ...
  4.  
  5.     canales.push_back(new L2capChannel(CID,PSM,(void*)this,&Wrapper_a_escribeEnSocket)); // Callback
  6.    
  7.  
  8. ....
  9.  
  10. }
  11.  



Y el canal, llamaba al wrapper desde el constructor del canal:

Código: Text
  1. L2capChannel::L2capChannel (int CID, int PSM,void* a, void(*pt2Func)(void*, std::string))
  2. {
  3.    _estado = CLOSED;
  4.    _localCID = CID;
  5.    _PSM = PSM;
  6.    _ME = a;
  7.    cout&#60;&#60;&#34;Se supone que enviamos!&#34;&#60;&#60;endl;  
  8.    pt2Func (_ME,&#34;080001000205040001004000&#34;); // Llama al Wrapper
  9. }
  10.  

A ver si me pudieseis ayudar con esto, ya por lo menos está localizado el error. Esta mas cerca de solucionarse :)

Muchísimas gracias por todo!
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Lunes 10 de Diciembre de 2007, 22:45
No se realmente donde encontraste el error. Yo lo depuro y esta correcto:

En main tenes un objeto llamado micapa de la clase L2cap cuya direccion en memoria es en mi caso 0x0012feec. Sigo la pila y llegamos a Openchannel_req donde se crea un objeto de tipo L2capChannel. En el constructor del mismo se recibe como tercer parametro un void * a cuyo valor en este caso tambien es 0x0012feec. Ese constructor llama a Wrapper_a_escribeEnSocket con un parametro void *pt2Object con el mismo valor de siempre, ahi mismo tenes un puntero a un objeto de la clase L2cap mediante un casting a la direccion de siempre. Con lo cual mySelf es lo mismo que &micapa del main. Eso llama a escribeEnSocket donde this ya es igual a &micapa/mySelf y SendBytes lo mismo. Por eso mismo me funciona perfectamente.

mySelf es un puntero a micapa y no necesitas cambiar ni asignar ningun valor en el, el socket es el mismo.

Depura (o usa alguna cadena para mostrar en pantalla) los puntos donde se crean, se cierran y se usan los sockets. Es la unica forma de comprender el problema realmente.
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Lunes 10 de Diciembre de 2007, 23:28
Es cierto. No se por que vi que ahí podría haber un error :(

Voy a ejecutar sacando información por pantalla de dichos momentos.
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Lunes 10 de Diciembre de 2007, 23:48
He puesto salidas por pantallas en los momentos que se crean los sockets, en el constructor de L2CAP.

Cuando hago un socketServer, da un numero hexadecimal.
Cuando hago SocketClient, s toma otro valor hexadecimal.

Y saco por pantalla también el contenido de s en escribeEnSocket, y dicho valor es el mismo que el que cuando hacía SocketClient, lo cual es correcto. Ese lugar es el único en el que se realiza un envío por el socket.(SendBytes).



Si saco por pantalla el valor de s en el bucle de leer socket, en ambos casos se imprime su valor correspondiente (en cliente el del cliente, y en servidor el del servidor).

¿todo esta correcto no?
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Lunes 10 de Diciembre de 2007, 23:52
Es probable, a mi me funciona, pero no se si comprobaste los puntos donde esos sockets se cierran. Si te dice que el socket no es valido es por una razon ... o es un numero totalmente al azar o ese socket fue cerrado con anterioridad.
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Martes 11 de Diciembre de 2007, 00:25
Bueno, ese es el contenido de la variable s, en el programa.

Si lo que saco por pantalla es, en socket.cpp, el valor de s_ (que es el socket, ¿no?), los valores obtenidos son diferentes.

Código: Text
  1. void Socket::SendBytes(const std::string& s)
  2. {
  3. send(s_,s.c_str(),s.length(),0);
  4. }
  5.  


Saca por pantalla que el valor de s_ es 64. (y 64, si lo pasamos a hexadecimal, es 40).

Si yo cojo, y en SendBytes modifico el valor de s_ al principio antes de hacer send, y le pongo el valor que debería de tener (es decir, el que mostraba por pantalla cuando era cliente), al ejecutar las cosas no son como deberían.

Le digo que: s_ = 0x22fe60; justo antes de hacer send.

Y lo mostrado por pantalla es, que el valor de s_ es igual a 2293344 ( que es 22fe60 en decimal) por lo tanto está correcto esto. Aunque al Servidor sicge sin llegarle nada.

Si le digo que el valor de s_ sea   s_ = 0x3d27e0; (que es el valor cuando es Servidor) tampoco ocurre nada.


Lo que es un poco mosqueante, es que, en la Tabla de registro de canales L2CAP, que se imprime en la ventana del Cliente, imprime los valores de los campos CID y PSM de la posición 0 del vector. Y dichos valores son los correctos (concretamente el CID es 40, lo cual es correcto puesto que es el primer valor que debe asignar).

Sin embargo, cuando he hecho los cambios de asignarle a s_ un nuevo valor distinto del que tenía para ver si envíaba algo, pue spor pantalla salía el valor modificado de s_, pero también se modificaba el valor de CID de la tabla!

Y no se por que porque aparentemente no tienen ninguna relación. Ambas están en partes distintas del código.  s_ se supone que es el socket, y CID es una variable que se supone que se asigna, independientemente de eso.

¿He encontrado algo útil?
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Martes 11 de Diciembre de 2007, 00:30
Si estas probando algo con el servidor por ahora olvidalo por completo, ejecutalo y no lo pruebes/depures, no tiene sentido. No se si encontraste algo ya que no se realmente que fue lo que hiciste. ¿Ya comprobaste los puntos donde se cierra el socket? No quiero repetir lo mismo 500 veces.
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Martes 11 de Diciembre de 2007, 00:43
Eternal Idol, siento de verdad mi torpeza en este problema. He intentado sacar toda la información que he podido obtener por pantalla.

No se con certeza el punto donde se cierran los sockets. La creación imagino que la he identificado correctamente, cuando definimos el socket en SocketClient y SocketServer. Pero el cierre, ... he buscado en la clase socket "close", y hay un closesocket(s_). He puesto que sacase una linea por pantalla informando del valor de s_ en el caso de que lo fuese a cerrar, pero no se ha imprimido por pantalla ningún valor, por lo tanto el socket no se ha cerrado.

Pido disculpas por no haber comprobado esto antes.
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Martes 11 de Diciembre de 2007, 00:46
Lo que hice antes fue, en el código de SendBytes en Socket.cpp, cambié el valor de s_ a un valor que le dí yo. Por pantalla mostraba dicho cambio, pero el cambio también afectaba al contenido del campo CID almacenado en la posición 0 del vector de la tabla de canales.

Eso es lo que explicaba en el post anterior.
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Martes 11 de Diciembre de 2007, 00:47
Bien, no se cierra. Se crea con la funcion socket(), buscala y comproba que su valor de retorno (se supone que se crea uno solo) sea exactamente el mismo que pasas a send() siempre (s_).
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Martes 11 de Diciembre de 2007, 00:59
En la búsqueda de "close" no había encontrado otros sitios donde se cerraba también el socket, al no ponerle que la búsqueda la realizara en totalidad del fichero, y no desde el cursor.

He puesto mensajes en todos los close, y he obtenido que en servidor, se crea el socket con s = 3d27e0 [s es la variable de l2cap], saca el mensaje de conexión recibida, t a continuación se produce un cierre de socket. Y el valor de s_ es DC (en hexa, que en decimal es 220).
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Martes 11 de Diciembre de 2007, 01:13
He puesto a sacar por pantalla también el valor de s_ en Socket(), y comprobado con el valor de s_ en Send(), y no son iguales.

En el cliente, lo primero que se realiza es Socket(), y el valor devuelto es D4.
A continuación, en cuanto saca por pantalla el mensaje de Conexión Recibida, saca un mensaje por pantalla de que se ha cerrado el socket, y el valor de s_ es DC.

Y luego se queda ahi, esperando nuevos datos, ...


En el cliente pos su parte, al principio lo que se hace también primero es Socket(), y el valor de s_ es D4. Y en el Send() el valor de s_ es 64. Y entonces a continuación saca por pantalla la información de error (-1) y el codigo (10038).
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Martes 11 de Diciembre de 2007, 09:23
Siempre hace las comprobaciones en el ambito de cada proceso (cliente y servidor) no sirve de nada comparar entre ambos ya que al ser otro proceso su tabla de handles es completamente independiente.

En el cliente si socket() y send() usan un diferente s_ es logico que falle, comproba todos los puntos donde se podria cambiar este valor. Lo mejor es que lo depures, desde el momento en que s_ es asignado por socket() - donde tiene que ser valido - hasta el momento en que cambia. En el servidor se usa un socket para escuchar y despues hay otro para conexion aceptada y con ese se comunica.
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Martes 11 de Diciembre de 2007, 15:16
Esta noche cuando regrese me pondré a intentar localizar el punto donde se cambia el valor de s_ en el Cliente.

De todas formas, se produce un cierre de socket en el servidor, tras mostrar la aceptación de la conexión (Conexión recibida). No se tendría por qué producir un cierre de socket, ¿no?


Para aislar el que esté teniendo problemas en el servidor o en el cliente, puedo probar a crear un programa a parte, que no tenga nada que ver con mi código, y que lo que haga sea por ejemplo escuchar por el mismo puerto 3000, y sacar por pantalla lo que reciba.

Y otro que lo que haga sea escribir algo por ese puerto, y así testearía el comportamiento del servidor l2cap. ¿no?

Debería funcionar y haber comunicación. Tan solo declarar SocketClient, y hacer un SendBytes, o declarar SocketServer, hacer un accept y un receivebytes.

Un saludo y en cuanto tenga resultados los comento. Muchísimas gracias de nuevo.
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Martes 11 de Diciembre de 2007, 23:29
Me dispongo a depurar el modo Servidor.

Elijo la opción servidor.
Se realizan una serie de acciones en allocator.h new_allocator.h y stl_vector.h, realizando reservas de memoria para el vector.

Después de esto, llegamos al constructor de L2CAP, y realiza las acciones de acuerdo con el modo elegido (servidor). Se realiza un SocketServer, al puerto 3000. sockaddr_in
Pasamos a Socket(), en la clase Socket.

Se llama a Start(). nofSockets y WSAStartup dice que no las encuentra en este contexto, con lo cual parece que no hace nada, y solo incrementa nofSockets, que indica lo mismo, que no la encuentra en el contexto. (Con lo cual aqui no se hace nada).


Seguimos en Socket(), y this->s_ (que es s_ en la clase socket) pasa a tomar el valor 1828.
refCounter_ vale 0x3d24d8. Salimos de Socket(), y seguimos en SocketServer, en memset.

sa.sin_family = 2
sa.sin_port = 47115

s_ = 1828


No detecta que sea un socket inválido, y tampoco entra en los bucles de que sea un NonBlockingSocket ni que se cumpla la condición de bind.... Seguimos por listen (s_,connections). [connections vale 5].

De ahi pasamos a Socket* sa=in.Accept(), que provoca irnos a Accept en Socket, y se queda ahi parado, esperando, en new_sock = accept (s_,0,0).

Paso ahora a ejecutar mi otro programa y a elegir modo cliente.

En ese momento, se produce un salto, y nos encontramos en la función Accept en SocketServer. Se llama a Start(). refcounter vale ahora 0xbaadf00d. Se devuelve el valor de r desde Accept en SocketServer, que es 0x3d2908.

Volvemos al constructor de L2CAP, y copiamos el valor de sa a s. Dicho valor es 0x22ff20. Imprime por pantalla el mensaje Conexion Recibida. Se coloca sobre _beginthreadex, y al darle a siguiente paso hace de nuevo SocketServer in (3000,5) ahi en el constructor de L2CAP. Se salta al destructor del socket. Se llama a Close, y éste hace closesocket(s_), y s_ vale 1828.

Se hace un delete refCounter en el destructor de Socket. El valor de refCounter es 0x3d24d8.

Volvemos a SocketServer in en el constructor de L2CAP, y se hace un salto al final del constructor y se sale de el. Quedando ya para siempre en el bucle del programa principal de mostrar por pantalla: "Sigo aqui en modo Servidor".



Desde luego que las acciones que hace ahi en el constructor de L2CAP no tienen ningún sentido, al menos no se lo veo. No se porque se destruye el socket, ni porqué se pasa a hacer de nuevo SocketServer. :(
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Martes 11 de Diciembre de 2007, 23:56
Tanto sentido como _escuchando = true; en la primera linea del constructor de L2cap pero es TU codigo. Todo ese constructor es erroneo ...

No se donde habras sacada esto:
Código: Text
  1.  
  2.   *(s) = sb; //Con esto hemos anclado el contenido del puntero y ya no se borra al salir del Constructor
  3.  

En cuanto termina ese constructor se llama al destructor de in o sb segun corresponda ...
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Miércoles 12 de Diciembre de 2007, 00:27
Esa línea la coloqué porque no sabía si el socket estaba siendo destruido en cuanto salía del constructor (cosa que efectivamente estaba pasando). Intenté remediarlo con esto, pero no vale para nada.

En cuanto al valor de la variable global escuchando la tengo inicializada ahí porque es una variable que necesito que desde la creación de mi nuevo objeto esté a true, para efectuar la lectura, y en el caso de que por el socket alguna vez reciba la cadena "exit", esa variable se pondrá a false, y se saldrá del bucle en el que se lee el socket contínuamente.


Lo que no entiendo es como el programa provoca unos resultados exitosos en tu ordenador, pero yo no logro hacerlo, y el comportamiento es totalmente erroneo. :(

Voy a intentar hacer dos constructores distintos, uno para el cliente y otro para el servidor. En lugar de hacer en el mismo constructor la distinción de si se le está pasando un 1 o un 2 para definir el comportamiento, aunque esto no deberñia de ser un problema, es un simple if, de una variable que se le pasa al constructor, ¿no?
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Miércoles 12 de Diciembre de 2007, 00:55
Al eliminar la línea siguiente

*(s) = sb; //Con esto hemos anclado el contenido del puntero y ya no se borra al salir del Constructor

 el error devuelto por getlasterror cambia, y ya no es 10038, sino 10093. He encontrado lo siguiente acerca de este error:

10093 WSANOTINITIALISED

"Successful WSAStartup not yet performed. Either the application has not called WSAStartup or WSAStartup failed. The application may be accessing a socket that the current active task does not own (that is, trying to share a socket between tasks), or WSACleanup has been called too many times."
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Miércoles 12 de Diciembre de 2007, 18:52
Tenes que arreglar ese constructor ... usa new para los objetos y no te olvides del delete correspondiente.

La diferencia es que se llama al operator = de la clase Socket y eso entre otras cosas aumenta la variable de las referencias (cuando no lo haces al ejecutarse el destructor y quedar sin referencias tambien se ejecuta End que llama a WSACleanup).
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Miércoles 12 de Diciembre de 2007, 22:16
He cambiado las definiciones de los objetos L2cap desde principal. Ahora lo realizo:

L2cap* micapa = new L2cap(1);

Por ejemplo. Y para referirme ahora a los métodos de mi clase, usaré -> en lugar de '.' solo.

Sin embargo el resultado de la ejecución sigue siendo el mismo.

No he entendido bien la última parte de tu último post, Eternal Idol.


Otra cosa que queria comentar es la siguiente. Ejecutando paso por paso, en depuración, observo que el comportamiento, tanto en el servidor como en el cliente es similar en cuanto a lo siguiente: en el constructor, se realizan todas las acciones correspondientes, pero cuando se llega a beginthreadex, da un salto a SocketServer (la primera línea del constructor de la clase) y de ahí pasa a la destrucción del objeto de la clase.

Eso ocurre tanto si elegimos que sea Cliente como si es Servidor. Y ocurre tanto con la definición realizada con new, como con la que tenía antes.

¿Es normal esto?
Ademas, si pongo entre comentarios la línea del beginthreadex (para comprobar si era debido a dicha instrucción), ocurre exactamente lo mismo, solo que el salto se realiza desde la línea anterior. Y si comento la anterior, se realiza desde la anterior (que es un simple cout ), ... No tiene ningún sentido.
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Miércoles 12 de Diciembre de 2007, 22:22
Tiene todo el sentido del mundo, lo que se llama es el destructor de los objetos locales que estan en la pila, en cuanto se acaba el constructor su ambito desaparece y por tanto se llama al destructor correspondiente (SocketServer/SocketClient). Lo que tenes que cambiar es el constructor mismo (L2cap::L2cap) como te dije antes.

La ultima parte de mi mensaje anterior explicaba la diferencia en los errores con y sin esa linea bizarra.
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Miércoles 12 de Diciembre de 2007, 23:07
¡Creo que lo logramos! He realizado también las creaciones de los objetos en el constructor de L2CAP para el socket, de la siguiente manera:

En el servidor:

       SocketServer* in = new SocketServer(3000,5);
       Socket* sa = in->Accept();
       s = sa;

En el cliente:

       SocketClient* sb = new SocketClient("localhost",3000);
       s = sb;

Y al hacer esto, ya hay transferencia correcta de información, y no se cierran los sockets. No me lo creia cuando lo veía.

Un millón de gracias Eternal Idol. De verdad, que no creía que lo pudiesemos solucionar, y mas pensando en que en tu máquina funcionaba el mismo código que en la mía no lo hacía. ¿Eso a qué podría haberse debido? Porque los constructores estaban igual de mal declarados antes. ¿Quizás por la forma de hacer las cosas del compilador?

En fin, muchísimas gracias de nuevo por todo, por haberte puesto con el código y haber tenido paciencia para soportar mis dudas y mis no comprobaciones. Mil gracias.

Un saludo muy grande desde Málaga.
Título: Re: Comunicación Por Sockets
Publicado por: Eternal Idol en Miércoles 12 de Diciembre de 2007, 23:36
De nadas, ahora revisa todo tu codigo teniendo en cuenta el ambito de las variables ;)
Título: Re: Comunicación Por Sockets
Publicado por: captaindanieo en Miércoles 12 de Diciembre de 2007, 23:37
Recibido!  :D  :comp: