Codigo Visual Basic 6

Hola gente, necesito que me hecheis un cable. Alguien sabe como hacer una pausa para algún proceso en visual?? tipo, wait o sleep, que hay en C, para darle tiempo a un proceso a que finalice, antes de que se siga ejecutando el for.

Private Sub sockservidoratiende_DataArrival(Index As Integer, ByVal bytesTotal As Long)

Dim j As Integer
sockservidoratiende(Index).GetData buf

For j = 0 To sockservidoratiende.Count - 1
sockservidoratiende(j).SendData buf
'este proceso de envio es demasiado lento (solo da tiempo a enviar 'el primero) y hay q entretenerlo para que termine de enviar antes de 'pasar al siguiente for.

Next

End Sub

Si alguien sabe alguna forma, necesito un cable. Gracias.

Salu2
Puedes usar DoEvents(), pero este no pausa la ejecución solo da tiempo a otros procesos, tendrías que meterlo en un bucle que controlase el tiempo.
El Sleep lo tienes en el API de Windows, pero sigues teniendo el problema de ¿que tiempo ponerle?, si las transmisiones van por Internet algunas pueden tardar 1 segundo y otras 3, además el Sleep te deja pillado el programa hasta que pase el tiempo.

Public Declare Sub Sleep Lib "kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)
Public Declare Function SleepEx Lib "kernel32" Alias "SleepEx" (ByVal dwMilliseconds As Long, ByVal bAlertable As Long) As Long

Estas seguro que el problema esta en que no le da tiempo a enviar el mensaje, cada objeto "sockservidoratiende" tiene su propio buffer, así que no debería interferir unos con otro.
¿De cuantos datos son los mensajes?

Saludos
Puedes hacer dos cosas:

1. (lo más fácil)

Inmediatamente después del envío, metes otro for...next del tipo:

for i=1 to 1000
next i

Esto para el proceso, hasta que ejecuta toda la estructura for...next. Es posible que necesites tanto tiempo que tengas que encadenar dos estructuras, para no desbordar la variable de control:

for i=1 to 10000000 (ahora no recuerdo el rango de una Long)
for j=1 to 1000
next j
next i

Este truco es muy fácil de implementar, pero tiene grandes inconvenientes:
- Todo el entorno gráfico de la aplicación (entre otras cosas), queda parado, con lo que será bastante molesto de cara al usuario.
- Dependerás de la velocidad del microprocesador. A mí me ha dejado de funcionar correctamente una aplicación al cambiarla de ordenador, pasándoa de un PIII a un PIV.

2. Método seguro:

Emplea el evento de socket 'sockservidoratiende_SendComplete' para encadenar los envíos.

Es un método completo (edito: completo = complejo) pero seguro 100%. Debes tener una cola, hacer un envío desde fuera del objeto, y vaciar el resto de la cola haciendo envío cada vez que se te ejecute este evento.

A tener en cuenta:
- Es posible que un envío no se ejecute nunca (fallo del socket, de la red, etc). Debes tener previsto un timer de Time-Out, cuya propiedad 'interval' debe ser mayor que el tiempo que toma enviar un telegrama.

- Llenar la cola por abajo y vaciarla por arriba (para mantener el orden de los telegramas)

- No sé, me dejo cosas. Hazte un motorcillo y juega un poco con él, hasta que te quede depurado del todo.



indasc escribió:Puedes usar DoEvents(), pero este no pausa la ejecución solo da tiempo a otros procesos, tendrías que meterlo en un bucle que controlase el tiempo.


Pues claro que la función DoEvents() no detiene la ejecución, hace todo lo contrario. Cuando un proceso está detenido en un bucle, si no tiene la función DoEvents() queda detenida toda la aplicación. Lo que hace DoEvents() es dejar que la aplicación pueda recibir eventos mientras está detenida en dicho bucle.

Yo no usuaría métodos que paren (sleep, wait, etc...) porque son muy molestos cara la interface de usuario. LOS PROCESOS HAY QUE EJECUTARLO TAN RÁPIDO COMO SEA POSIBLE. Lo que yo haría (después de años programando en VB6) es tomar el 2º método que te explico. Es complejo y te irá dando algunas sorpresas. Pero si lo depuras bien, el motor que envía telegramas te quedará 100% robusto (o casi).

Suerte y saludos


indasc escribió:Estas seguro que el problema esta en que no le da tiempo a enviar el mensaje, cada objeto "sockservidoratiende" tiene su propio buffer, así que no debería interferir unos con otro.
¿De cuantos datos son los mensajes?


Te aseguro que con esa estructura el chaval está perdiendo telegramas.


Edito:

me dejo otro truco:

3. Con un timer.

- Pon un timer cuya propiedad interva sea mayor que el tiempo que se tarda en enviar un telegrama.

- Por defecto mantenlo con enabled = false. Para enviar, canvia su propiedad a enabled = true.

- Que el envío se haga llamado desde el evento Timer1_Timer, asegurándote antes de enviar que ya se ha enviado el último mensaje. Manera de asegurarte:

- poner una variable que se ponga a false en el evento 'sockservidoratiende_SendComplete', y a true en el evento 'Timer1_Timer' (antes de enviar). Esta variable te dirá si hay un envío en proceso.

Ten en cuenta que con este método seguirás necesitando el timer de control de time-out.



Este método es algo más sencillo que el 2º/, pero también tendrás que depurarlo algo.


En fin....mucha suerte. (siento explicarme tan mal)
[tadoramo] [tadoramo]
SrLOBO escribió:Pues claro que la función DoEvents() no detiene la ejecución, hace todo lo contrario. Cuando un proceso está detenido en un bucle, si no tiene la función DoEvents() queda detenida toda la aplicación. Lo que hace DoEvents() es dejar que la aplicación pueda recibir eventos mientras está detenida en dicho bucle.

DoEvents() da tiempo de CPU al resto de los procesos, incluida la propia aplicación que lo ejecuta, así no parece que se ha quedado colgada y puede hacer un bucle simulando un sleep sin los inconvenientes de usar el sleep real, esto seria como tu 1º solución pero hecho en condiciones y sin problemas al cambiar a equipos mas/menos potentes.

La segunda solución que propones es mucho mejor, aunque con lo complejo que seria usando el winsock, casi seria mejor implementarlo utilizando las funciones para sockets del API de Windows.

La tercera solución tiene el problema que el tiempo es muy variable, sobre todo si la transmisión es por Internet, lo que implicaría un tiempo muy grande entre mensajes para asegurarse.

SrLOBO escribió:Te aseguro que con esa estructura el chaval está perdiendo telegramas.

Pues si pierde paquetes por enviarlos seguidos, el control winsock es una p*** mierda.
Yo lo use hace tiempo para un programa de chat en lan, eran 2 programas, cliente y servidor, los clientes enviaban los mensajes al servidor y este los mandaba a los clientes en un bucle igual al de él y ni un fallo en las transmisiones.
El único problema que me daba era mandando muchos datos, creo que solo podía mandar unos 4 KBs, si mandaba mas los cortaba y enviaba en varios cachos, por eso le pregunte el tamaño de los datos que envía.

Saludos
DoEvents no da tiempo a otros procesos. Windows es un sistema operativo multitarea, y los procesos se ejecutan en multitarea exclusivamente gracias a windows. Puedes establecer prioridades para que procesos se ejecuten con mayor prioridad que otros, pero desde luego, no con la función DoEvents.

DoEvents lo que hace es permitir que tu aplicación (que se ejecuta en el mismo proceso que el bucle for...next en cuestión) no quede parada por culpa de éste, y puede recibir, y por lo tanto ejecutar, otros eventos que le envía el sistema operativo (como el click de un boton, etc.).

Esta es una manera yo diría casi que 'suicida' de ejecutar un procedimiento o función, porque se pueden ejecutar las funciones de manera recurrente, con el peligro de que la aplicación quede colgada.

Si tu no tuviste problemas con el for..next, era porque enviabas dentro del mismo bucle a clientes distintos, con lo que se recibían en sockets distintos. El control winsock tiene un búffer de recepción que puede ser llenado sin previamente ser vaciado. El buffer de envío, sin embargo, no funciona de la misma manera. Mientras el socket está ocupando con una Tx, el buffer no puede volver a ser llenado, porque estos datos se pierden. No es que sea un puta mierda, se trata de conocerlo y mejorarlo para que se ajuste a tus necesidades. Si no, siempre tienes la opción de usar la API, pero seguro que eso te mola menos.


indasc escribió:La segunda solución que propones es mucho mejor, aunque con lo complejo que seria usando el winsock, casi seria mejor implementarlo utilizando las funciones para sockets del API de Windows.


Yo no veo eso nada complicado. Ya te dijo, se trata de depurarlo un poco y nada más. Es más, tengo dos motores (un cliente y otro servidor) hechos de esta manera, y que funcionan de pm, y tan complicado no los veo...
SrLOBO escribió:DoEvents no da tiempo a otros procesos. Windows es un sistema operativo multitarea, y los procesos se ejecutan en multitarea exclusivamente gracias a windows. Puedes establecer prioridades para que procesos se ejecuten con mayor prioridad que otros, pero desde luego, no con la función DoEvents.

Haz un bucle sin DoEvents() y mientras se ejecuta intenta trabajar con otras aplicaciones y veras lo bien que gestiona Windows la multitarea.
Luego ejecuta el mismo bucle incluyendo un DoEvents(), veras que es como si el bucle no se estuviera ejecutando, aunque la CPU este al 100% de uso.

Contra menos potente sea el equipo mas se nota la diferencia.

SrLOBO escribió:Esta es una manera yo diría casi que 'suicida' de ejecutar un procedimiento o función, porque se pueden ejecutar las funciones de manera recurrente, con el peligro de que la aplicación quede colgada.

Es una chapuza si se ejecuta dos veces el mismo proceso mientras ya esta en ejecucion, pero es facil controlarlo, con una variable que impida que se ejecute dos veces el mismo proceso vale.

SrLOBO escribió:Si tu no tuviste problemas con el for..next, era porque enviabas dentro del mismo bucle a clientes distintos, con lo que se recibían en sockets distintos.

El cacho de codigo que ha puesto es igual al que use yo.
1 control winsock = 1 socket.
Esta utilizando un array de controles winsock, no entiendo donde ves un solo cliente que reciba todos los mensajes.

SrLOBO escribió:El buffer de envío, sin embargo, no funciona de la misma manera. Mientras el socket está ocupando con una Tx, el buffer no puede volver a ser llenado, porque estos datos se pierden. No es que sea un puta mierda, se trata de conocerlo y mejorarlo para que se ajuste a tus necesidades.

Deacuerdo, pero es que esta usando controles winsock distintos, no el mismo para enviar mensajes continuamente.

For j = 0 To sockservidoratiende.Count - 1
sockservidoratiende(j).SendData buf

Saludos
Si la multitarea de windows no te gusta, usa otro sistema operativo. Desde Windows NT, el rendimiento de una aplicación no influye en el resto del sistema, ni mucho menos en el resto de aplicaciones.

Paso ya de este rollo. El chaval ha pedido sugerencias y yo se le he dado las mías, que son las que hace tiempo utilizo y funcionan sin nigún problema. Por mi parte, no las veo complicadas.

Este hilo no va de esto, y no estamos ayudando en nada al que lo ha creado.
indasc escribió:Yo lo use hace tiempo para un programa de chat en lan, eran 2 programas, cliente y servidor, los clientes enviaban los mensajes al servidor y este los mandaba a los clientes en un bucle igual al de él y ni un fallo en las transmisiones.


Pues eso mismo es lo que estamos haciendo, un programa de chat sencillito, y el problema es por el tiempo, lo que tengo hecho, es que cada vez que se conecta un cliente a mi servidor, este crea un socket para atenderle, y tengo otro permanentemente escuxando, y claro, quería saber si había alguna forma para dar tiempo al proceso, a que enviase todos los datos, xq tal y como está, si lo ejecutas por partes (poniendo algún punto de interrupción, para ir viendo lo que hace), lo envía a todos, xo si se ejecuta desde el ejecutable, pues ya no envía a los demás. Sobre las ideas que me habeis dado, cosa que agradezco, alguna ya se me había ocurrido, incluso, alguna chapucilla más, xo weno, quería hacerlo sin xapucillas.

Y ya que estoy con estas cosultas, tengo otro pequeño problema, tengo este código:

Private Sub sockservidor_ConnectionRequest(ByVal requestID As Long)
Static i As Integer

'genera un array de controles para los sockets
'se generan sockets automáticamente
If i > 0 Then
Load sockservidoratiende(i)
End If

'aceptar las peticiones de los clientes
'cada cliente tiene un request diferente y un socket que lo atiende
sockservidoratiende(i).Accept requestID

'aquí añado a un list los clientes que están conectados en el servidor
List1.AddItem sockservidoratiende(i).RemoteHostIP

'incremento i para crear nuevos sokets para atender
i = i + 1
End Sub

Esto crea los sockets para atender a los clientes, xo es un array de controles y lo que sucede es que cuando un cliente se va, deja un "hueco", y al enviar a ese cliente, pues falla, ya que no está, he pensado en hacer una búsqueda del cliente que se ha ido, y una vez que lo encuentre, enviar a todos menos al que no esté, vamos, que tendría que estar buscando continuamente con un bucle, para comprobar los clientes que están y los que no. Sería algo así.

Gracias nuevamente.

Salu2

PD: Podeis discutir los procedimientos, xo no opineis sobres cual es mejor o peor, ya que cada uno programa de forma distinta, y por lo tanto, le gusta más una forma u otra, xo lo que importa, son las ideas. Gracias y a cuidarse.
Zokko escribió:Pues eso mismo es lo que estamos haciendo, un programa de chat sencillito, y el problema es por el tiempo, lo que tengo hecho, es que cada vez que se conecta un cliente a mi servidor, este crea un socket para atenderle, y tengo otro permanentemente escuxando

Hasta aqui bien, 1 socket que escucha las peticiones de conexion y x sockets para el envio y recepcion de datos entre los clientes y el servidor.

Zokko escribió:y claro, quería saber si había alguna forma para dar tiempo al proceso, a que enviase todos los datos, xq tal y como está, si lo ejecutas por partes (poniendo algún punto de interrupción, para ir viendo lo que hace), lo envía a todos, xo si se ejecuta desde el ejecutable, pues ya no envía a los demás. Sobre las ideas que me habeis dado, cosa que agradezco, alguna ya se me había ocurrido, incluso, alguna chapucilla más, xo weno, quería hacerlo sin xapucillas.

Sigo sin entender el por que de darle tiempo, estas utilizando un objeto para no tener que preocuparte de esas cosas.
Solo tienes que ejecutar el SendData con el mensaje que quieras enviar, eso metido en un bucle que recorra los "x sockets".
Aparte de eso solo tienes que preocuparte de controlar los eventos que producen los "x sockets", el Close (asi sabras cuando se va un usuario), el DataArrival (para saber cuando llega un mensaje) y el Error (por si se produce alguno).
Para comprobar que realmente es por el tiempo, usa el Sleep que te puse al principio, eso si solo usalo para probar no como solucion final.

Aqui te pego como lo hice, yo tenia los objetos socket creados desde el principio en un formulario, estaba pensado para muy pocas conexiones, asi que para no complicarme lo hice asi.
___'Envia el Mensaje a Todos Los Clientes
___For I = 1 To frmPrincipal.sokCliente.Count
______With frmPrincipal.sokCliente(I)
_________If .State = sckConnected Then
____________'Hay Un Usuario Conectado
____________'Le Envia el Mensaje
____________.SendData Mensaje
_________End If
______End With
___Next

Zokko escribió:Y ya que estoy con estas cosultas, tengo otro pequeño problema, tengo este código:

Private Sub sockservidor_ConnectionRequest(ByVal requestID As Long)
Static i As Integer

'genera un array de controles para los sockets
'se generan sockets automáticamente
If i > 0 Then
Load sockservidoratiende(i)
End If

'aceptar las peticiones de los clientes
'cada cliente tiene un request diferente y un socket que lo atiende
sockservidoratiende(i).Accept requestID

'aquí añado a un list los clientes que están conectados en el servidor
List1.AddItem sockservidoratiende(i).RemoteHostIP

'incremento i para crear nuevos sokets para atender
i = i + 1
End Sub

Esto crea los sockets para atender a los clientes, xo es un array de controles y lo que sucede es que cuando un cliente se va, deja un "hueco", y al enviar a ese cliente, pues falla, ya que no está, he pensado en hacer una búsqueda del cliente que se ha ido, y una vez que lo encuentre, enviar a todos menos al que no esté, vamos, que tendría que estar buscando continuamente con un bucle, para comprobar los clientes que están y los que no. Sería algo así.

Esto te lo acabo de contestar, cuando se ejecuta el evento Close es que se ha cerrado la conexion.
Tambien puedes comprobar el valor de .State si no es igual a sckConnected, es que el socket esta cerrado.

Saludos
8 respuestas