Understanding Sockets

Arokh

Well-known member
Joined
Apr 11, 2006
Messages
124
Hi
Since I made myself comfortable in VB 05 and it is going well so far,
I want to give a try to make some chatclient & -server.

So far I accomplished, by reading through the forum and the msdn, to make a TcpListener and TcpClient by copying the code. I already made some experiments with it and changed the code to make it more useful for my purposes.

[VB]Imports System
Imports System.IO
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports Microsoft.VisualBasic

Public Class frmClient
Public Client As New TcpClient
Public Stream As NetworkStream

Private Sub Connect(ByVal server As [String], ByVal port As Int32)
Try
Client.Connect(server, port)
Stream = Client.GetStream
Catch e As ArgumentNullException
Debug.Print("ArgumentNullException: {0}", e)
Catch e As SocketException
Debug.Print("SocketException: {0}", e)
End Try
Debug.Print(ControlChars.Cr + " Press Enter to continue...")
End Sub

Private Sub SendMsg(ByVal Message As String)
Dim data As [Byte]() = System.Text.Encoding.ASCII.GetBytes(Message)
Stream.Write(data, 0, data.Length)

Debug.Print("Sent: {0}", Message)
End Sub

Private Sub CloseConnection()
Client.Close()
End Sub

Private Function RecieveMsg() As String
Dim Data = New [Byte](256) {}

Dim responseData As [String] = [String].Empty

Dim bytes As Int32 = Stream.Read(Data, 0, Data.Length)
responseData = System.Text.Encoding.ASCII.GetString(Data, 0, bytes)
Debug.Print("Received: {0}", responseData)
RecieveMsg = responseData
End Function

Private Sub frmClient_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Connect("127.0.0.1", 13000)
SendMsg("Bla")
RecieveMsg()
CloseConnection()
End Sub
End Class[/VB]
[VB]
Imports System
Imports System.IO
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports Microsoft.VisualBasic

Public Class frmServer
Public stream As NetworkStream
Public Sub Main()
Try
Dim port As Int32 = 13000
Dim localAddr As IPAddress = IPAddress.Parse("127.0.0.1")
Dim server As New TcpListener(localAddr, port)
server.Start()
Dim bytes(1024) As [Byte]
Dim data As [String] = Nothing
While True
Debug.Print("Waiting for a connection... ")
Dim client As TcpClient = server.AcceptTcpClient()
Debug.Print("Connected!")
data = Nothing
stream = client.GetStream()
Dim i As Int32

i = stream.Read(bytes, 0, bytes.Length)
While (i <> 0)
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i)
Debug.Print([String].Format("Received: {0}", data))
data = data.ToUpper()
Dim msg As [Byte]() = System.Text.Encoding.ASCII.GetBytes(data)
stream.Write(msg, 0, msg.Length)
Debug.Print([String].Format("Sent: {0}", data))

i = stream.Read(bytes, 0, bytes.Length)

End While

End While
Catch e As SocketException
Debug.Print("SocketException: {0}", e)
End Try

Debug.Print(ControlChars.Cr + "Hit enter to continue...")
Console.Read()
End Sub Main
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Main()
End Sub
End Class[/VB]

With this I could connect to the TCPListener send some message,
then the Listener would send a message back and the client recieves it.
But this only works when each side gets an answer otherwise it waits forever.
Since I have to be able to get and send messages, for a Chatclient, simutanously
this isnt the best solution :).
Ive read that I have to make an asynchronous connection,
but I couldnt find enough information to get me started.

So besides some tutorials you could link me to, I have some questions:
1. If I make an asynchronous connection can I recieve and send data/text with only one open port from more then one IP?
I guess thats the case since for programs like mIRC,
 
Typically you would use threading to get round the problem of blocking, a single listener would wait for incomming connections and spawn a new thread to handle the communication - search these forums and you should find some examples.
Regardless of asynchronus or synchronus connections if you are using TCP then it is a single IP/Port to a single IP/Port - there isnt a way to have multiple connections using the same port (this isnt the same if you are using UDP based broadcasts or multicast packets though).

The main reason for synchronus connections is simplicity - you do not have to worry about responding to incomming data etc.

Stream.Read returns the number of bytes read into the buffer - for network connections there is no simple way to determine how much data is left as the other end could keep adding more data anyway...

Stream.Write sends the data to the underlying connection, closing the stream will flush any unsent data...

http://msdn2.microsoft.com/en-US/library/system.io.stream(VS.80).aspx may be worth a read regarding the Stream class.
http://www.cisco.com/warp/public/535/4.html and http://www.doc.ic.ac.uk/~ih/doc/pc_conn/tcpip/intro/intro0.html are probably also worth reading as they will answer some of the networking questions.
 
Thank you for answering all my questions.

But Im quiet confused with this statement:
Regardless of asynchronus or synchronus connections if you are using TCP then it is a single IP/Port to a single IP/Port - there isnt a way to have multiple connections using the same port

Because a Program like
 
The port a process listens on is how a client will make its initial connection, i.e. a web server listens (by default anyway) on port 80. When a client needs to communicate with the server it will make its initial connection to the server on this port.
As part of the connection handshake the client and server will negotiate another set of port numbers to communicate on and these are the ports used for the remainder of the conversation.

These negotiated port numbers are not however treated as new connections as they are part of the existing connection that happened to start on port 80 - therefore they are not blocked by your firewall etc. as they are not incoming requests.

The scenario I suggested above of using seperate threads for each connection will work but this can cause scalability issues if the number of connections gets large as you will end up with a large number of threads, a lot of which will be idle for large portions of the time.
In this scenario rather than a one client = one thread model you would find using async sockets more scalable as you would only need to allocate resources as and when data arrives.
 
Back
Top