|
-
Aug 15th, 2003, 09:30 AM
#1
Thread Starter
Addicted Member
Socket Problems [Resolved]
Hi all,
Sorry to post a big chunk of code like this and ask 'what’s wrong', it seems lazy, but I've read as much as I can find and I still can't figure out how to fix this... I'm stuck!
I'm trying to write a client program which will send data to a server program, waits for a reply and then receives the data sent from the server.
Here's my code, it works if I step through it slowly in debugging mode, but not if I run it normally.
VB Code:
Const READ_BUFFER_SIZE As Integer = 255
Const PORT_NUM As Integer = 2100
Private client As TcpClient
Private readBuffer(READ_BUFFER_SIZE) As Byte
Private Sub SendData(ByVal data As String)
client = New TcpClient("localhost", PORT_NUM)
client.ReceiveTimeout = 500
' Send request to server
Dim writer As New IO.StreamWriter(client.GetStream)
writer.Write(data & vbCr)
writer.Flush()
' Receive reply and display in messagebox
Dim networkStream As NetworkStream = client.GetStream()
Dim bytes(client.ReceiveBufferSize) As Byte
Dim returndata As String
While networkStream.DataAvailable
networkStream.Read(bytes, 0, CInt(client.ReceiveBufferSize))
returndata = returndata & Encoding.ASCII.GetString(bytes)
End While
networkStream.Close()
MsgBox(returndata)
client.Close()
client = Nothing
End Sub
Hopefully someone out there has some expertise with socket programming and can help me out.
Thanks!
Justin.
Last edited by Justy; Aug 26th, 2003 at 03:21 AM.
-
Aug 16th, 2003, 10:53 AM
#2
I wonder how many charact
Justy I feel your pain... I ran into a similiar situation a few months back...
I ultimately "fixed" it I believe using the NoDelay parameter so the data was written immediately without waiting for the buffer to fill... also, perhaps you need to increase your timeout amounts..
-
Aug 19th, 2003, 09:34 AM
#3
Thread Starter
Addicted Member
Hi nemaroller,
Thanks for your suggestion. I've set the nodelay property but it hasn't completely fixed my problem.
The problem seems to be that the function attempts to read what the server has sent before the server has even finished processing the message and sending it's reply. So basically it's returning nothing because it's reading too soon!
Now, I could insert a sleep function but that would be quite inefficient and still might be not be enough time if the server decides to send a large chunk of XML for example.
With VB6/Winsock I could handle the server response using the data received event but I don't have that luxury here.
Does anyone else have any additional insights??
Thanks!
Justin.
-
Aug 19th, 2003, 02:59 PM
#4
Hyperactive Member
I took your example and ran it, I don't know if you have any specific reasons you wanted to use a Instance of a networkstream or a streamwriter, but if you don't, you can use this , tested it and it works fine for what you seem to want to do...
Code:
Imports System
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports System.IO
Imports System.Threading
Public HOST_NAME As String = "localhost"
Public PORT_NUM As Int32 = 5050
Public Client As TcpClient = Nothing
Public PacketSize As Int32 = 512
Private Sub SendData(ByVal data As String)
Dim Buffer As Byte() = Nothing
Try
'Connect and send the data
Client = New TcpClient(HOST_NAME, PORT_NUM)
Buffer = Encoding.ASCII.GetBytes(data)
Client.GetStream.Write(Buffer, 0, Buffer.Length)
'Receive the data
ReDim Buffer(PacketSize - 1)
Dim SB As New StringBuilder
Dim ByteCount As Int32
'Get the data
ByteCount = Client.GetStream.Read(Buffer, 0, PacketSize)
SB.Append(Encoding.ASCII.GetString(Buffer, 0, ByteCount))
'If more data is being send (big packet)
While Client.GetStream.DataAvailable
ByteCount = Client.GetStream.Read(Buffer, 0, PacketSize)
SB.Append(Encoding.ASCII.GetString(Buffer, 0, ByteCount))
End While
'Show the text
MsgBox(SB.ToString)
'Shut it down
Client.Close()
Catch ex As Exception
End Try
End Sub
Last edited by Hinder; Aug 19th, 2003 at 03:21 PM.
-
Aug 21st, 2003, 04:34 AM
#5
Thread Starter
Addicted Member
Thanks hinder!
I also removed the StreamWriter from the server side and everything is working as expected. I suspect using a sample chat program wasn't the best start for what I wanted to program...
-
Aug 22nd, 2003, 10:42 AM
#6
Thread Starter
Addicted Member
Unfortunately with a little more testing... the problem has not gone away. Things work ok with small amounts of data, but when something a little larger is sent, it is only partially received.
I'm beginning to get a bit sick looking at this. Does anyone have any other suggestions before I go and buy a book on socket programming????
Thanks everyone.
-
Aug 22nd, 2003, 10:57 AM
#7
Hyperactive Member
Originally posted by Justy
Unfortunately with a little more testing... the problem has not gone away. Things work ok with small amounts of data, but when something a little larger is sent, it is only partially received.
I'm beginning to get a bit sick looking at this. Does anyone have any other suggestions before I go and buy a book on socket programming????
Thanks everyone.
Hmm, sorry to hear it doesn't work.. I didn't test it with large amounts of data, I honestly think if you're going to be working with alot of data, use asyncronous sockets for your code.. It's alot easier to handle sliced up data over the wire. Give me a bit and I'll whip you something up that should work..
-
Aug 22nd, 2003, 11:41 AM
#8
Hyperactive Member
VB Code:
While networkStream.DataAvailable
networkStream.Read(bytes, 0, CInt(client.ReceiveBufferSize))
returndata = returndata & Encoding.ASCII.GetString(bytes)
End While
I don't think this is a good way to get data from a stream. You should use the async methods as Hinder said. But if you want to keep this code, try changing it in:
VB Code:
While networkStream.DataAvailable
networkStream.Read(bytes, 0, CInt(client.ReceiveBufferSize))
returndata = returndata & Encoding.ASCII.GetString(bytes)
Threading.Thread.CurrentThread.Sleep(100) ' Delay of 100ms
End While
The problem in fact is that the server sends data slowly and your program gets data really fast. After the beginning chunks of data, your program gets an empty buffer and exits this loop. Try stopping here a little to have a chance to get more data. This is only a workaround and I don't suggest to keep this. Using socket can be a very pain, you must feel sockets...
Hope this helps.
Xmas79
Learn, this is the Keyword...
-
Aug 22nd, 2003, 12:33 PM
#9
Hyperactive Member
Ok I just finished this... It works on my end.. It's kinda how I built my server/client for my online game I'm working on.. Few things you gotto do.. first off this is a class.. or you can compile it as a component, doesn't matter whcih way.. just do this in your form....
Public WithEvents Client As New ClientSocket
Now on your form you will see the new ClientEvent in the list.. pretty self explanatory..
You need to set the address of where you want to connect and port..
Next big thing is you need to figure out what Delimiter the server is using to split the packets up, alot of servers use the CrLf or Chr(0) or Chr(1), it's up to you, but you need to be able to tell where the end of the packet is, so set the EOP value to that and it will work fine.. let me know if it needs anything..
VB Code:
Imports System
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports System.Threading
Public Class SocketState
#Region " Declares "
Public Socket As Socket = Nothing
Public Const PacketSize As Int32 = 1024
Public rBuff(PacketSize - 1) As Byte
Public sBuff() As Byte = Nothing
Public SB As New StringBuilder
#End Region
End Class
Public Class ClientSocket
#Region " Declares "
Private Const ServPort As Int32 = 5050
Private Const ServAddy As String = "localhost"
Private Const EOP As String = "<EOP>" 'End of Packet
Private doContinue As New ManualResetEvent(False)
Private MyState As SocketState = Nothing
#End Region
#Region " Events "
Public Event onReceive(ByVal inMsg As String)
Public Event onError(ByVal inMsg As String)
Public Event onFailedConnect(ByVal inMsg As String)
Public Event onDisconnect(ByVal inMsg As String)
Public Event onConnect()
#End Region
#Region " Methods "
Public Sub New()
'Default Constructor
End Sub
Public Sub Start()
'Start the connection on its own thread
Dim t As New Thread(AddressOf StartConnect) : t.Start()
End Sub
Private Sub StartConnect()
'Find the server endpoint
Dim ipHostEntry As IPHostEntry = Dns.GetHostByName(ServAddy)
Dim ipAddress As IPAddress = ipHostEntry.AddressList(0)
Dim ipEndPoint As New IPEndPoint(ipAddress, ServPort)
'Set up the socket
Dim Connector As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
Try
'Kill the state object just in case
MyState = Nothing
'Reset the thread pause
doContinue.Reset()
'Begin trying to connect
Connector.BeginConnect(ipEndPoint, AddressOf FinishConnect, Connector)
'Pause this thread
doContinue.WaitOne()
Catch ex As Exception
RaiseEvent onFailedConnect("A connection to the remote host could not be established.")
End Try
End Sub
Private Sub FinishConnect(ByVal ar As IAsyncResult)
Dim Handler As Socket = CType(ar.AsyncState, Socket)
Try
If Handler.Connected Then
'End the connection attempts
Handler.EndConnect(ar)
'Set up the new state
MyState = New SocketState
MyState.Socket = Handler
'Begin receiving
Handler.BeginReceive(MyState.rBuff, 0, MyState.PacketSize, SocketFlags.None, AddressOf ReceiveLock, MyState)
'Let the client know we connected
RaiseEvent onConnect()
Else
CloseSocket()
RaiseEvent onFailedConnect("A connection to the remote host could not be established.")
End If
Catch
CloseSocket()
RaiseEvent onFailedConnect("A connection to the remote host could not be established.")
Finally
'Restart the main thread
doContinue.Set()
End Try
End Sub
Private Sub ReceiveLock(ByVal ar As IAsyncResult)
Dim State As SocketState = CType(ar.AsyncState, SocketState)
Dim Handler As Socket = State.Socket
Dim ByteCount As Int32
Try 'Reteive the data
ByteCount = Handler.EndReceive(ar)
If ByteCount > 0 Then
State.SB.Append(Encoding.ASCII.GetString(State.rBuff, 0, ByteCount))
Dim Msg As String = State.SB.ToString()
If Msg.IndexOf(EOP) > -1 Then
RaiseEvent onReceive(Msg.Substring(0, Msg.IndexOf(EOP)))
State.SB.Remove(0, Msg.IndexOf(EOP) + EOP.Length)
End If
'Receive more data
Handler.BeginReceive(State.rBuff, 0, State.PacketSize, SocketFlags.None, AddressOf ReceiveLock, State)
Else
RaiseEvent onDisconnect("Connection closed by server.")
CloseSocket()
End If
Catch ex As Exception
RaiseEvent onError(ex.Message)
CloseSocket()
End Try
End Sub
Public Sub SendData(ByVal inMsg As String)
If MyState.Socket.Connected Then
'Package up the message
MyState.sBuff = Encoding.ASCII.GetBytes(inMsg.Trim)
Try 'Send the message
MyState.Socket.BeginSend(MyState.sBuff, 0, MyState.sBuff.Length, SocketFlags.None, AddressOf SendLock, MyState)
Catch ex As Exception
RaiseEvent onError(ex.Message)
End Try
End If
End Sub
Private Sub SendLock(ByVal ar As IAsyncResult)
'Stop the send request
Dim State As SocketState = CType(ar.AsyncState, SocketState)
Dim Handler As Socket = State.Socket
Dim BytesSent As Int32 = Handler.EndSend(ar)
End Sub
Public Sub CloseSocket()
'Shut down the clients socket
If (Not MyState Is Nothing) AndAlso (Not MyState.Socket Is Nothing) Then
'Ignore errors
On Error Resume Next
'Shut it down
MyState.Socket.Shutdown(SocketShutdown.Both)
MyState.Socket.Close()
MyState.Socket = Nothing
End If
'Destroy the state
MyState = Nothing
End Sub
#End Region
End Class
-
Aug 26th, 2003, 03:23 AM
#10
Thread Starter
Addicted Member
thanks for your help fellas, especially hinder.. all seems right again
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|