Simple Chat+ Picture Transfer

Katia Ppd Jakal

New member
Joined
Jan 6, 2012
Messages
1
Location
Athens, Greece, Greece
Programming Experience
Beginner
I have completed those 2 different windows applications a simple client server chat and a client server picture transfer too now i need to make them work together the same time with using only 1 timer and the sockets available to the old programms ive only managed to make a part of the programm to work here is the code :


Client code
VB.NET:
Imports System.NetImports System.Net.Sockets
Public Class frmClient
    Private tcpClient As Socket
    Private remoteIPAddress As IPAddress
    Private remoteEndPoint As IPEndPoint
    Private isFileSizeFlag As Boolean
    Private longFileSize As Long
    Dim incomingFile() As Byte
    Dim incomingDataSize As Long
    Dim received As Long


    Dim type As Integer = 2
    'type = 0 for a file
    'type = 1 for the file size message
    'type = 2 for chat
    
    Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
        type = 2
        Dim conStoB As New System.Text.ASCIIEncoding
        If txtSend.TextLength > 0 Then


            tcpClient.Send(conStoB.GetBytes(txtSend.Text, 0, txtSend.TextLength), txtSend.TextLength, SocketFlags.None)
            txtShow.Text = txtShow.Text & "Client says: " & txtSend.Text
            txtShow.Text = txtShow.Text & vbNewLine
            txtSend.Text = ""
        End If
    End Sub


    Private Sub btnConnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConnect.Click
        remoteIPAddress = IPAddress.Parse(txtIP.Text)
        remoteEndPoint = New IPEndPoint(remoteIPAddress, 1001)
        tcpClient = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
        tcpClient.Connect(remoteEndPoint)


        Timer1.Start()
    End Sub


    Private Sub btnDisconnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDisconnect.Click
        tcpClient.Close()
        Timer1.Stop()
    End Sub


    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Dim receivedBytes() As Byte
        Dim conBtoS As New System.Text.ASCIIEncoding
        Dim conStoB As New System.Text.ASCIIEncoding
        Dim incomingMessage() As Byte
        Dim k As Long = 0
        Dim bm As Image


        If tcpClient.Available > 0 Then
            If type = 2 Then 'apo default to type einai 2 epeidi stelnei keimeno
                ReDim receivedBytes(tcpClient.Available)
                tcpClient.Receive(receivedBytes, SocketFlags.None)
                txtShow.Text = txtShow.Text & "Server says: " & conBtoS.GetString(receivedBytes)
                txtShow.Text = txtShow.Text & vbNewLine


            ElseIf type = 0 Then


                If isFileSizeFlag = True Then
                    ReDim incomingMessage(tcpClient.Available - 1)
                    tcpClient.Receive(incomingMessage, tcpClient.Available, SocketFlags.None)
                    longFileSize = CLng(conBtoS.GetString(incomingMessage, 0, incomingMessage.Length))
                    isFileSizeFlag = False
                    tcpClient.Send(conStoB.GetBytes("OK", 0, Len("OK")), Len("OK"), SocketFlags.None)
                    ReDim incomingFile(longFileSize)
                    tcpClient.ReceiveBufferSize = longFileSize
                    tcpClient.Receive(incomingFile, tcpClient.Available, SocketFlags.None)
                    type = 2
                    'received = received + incomingDataSize


                    '  If received = longFileSize Then
                    If longFileSize > 0 Then type = 1 'if the file is bigger than 0 then
                    'make type = 1 the programm took the file's size and it waits for an aprooval


                    If type = 1 Then
                        FileOpen(1, Application.StartupPath & "\received.jpg", OpenMode.Binary, OpenAccess.Write)
                        FilePut(1, incomingFile)
                        FileClose()
                        bm = Image.FromFile(Application.StartupPath & "\received.jpg")
                        pictTransfer.Image() = bm
                        isFileSizeFlag = True
                    End If
                Else




                    incomingDataSize = tcpClient.Available
                    tcpClient.Receive(incomingFile, tcpClient.Available, SocketFlags.None)


                    received = received + incomingDataSize


                    If received = longFileSize Then


                        FileOpen(1, Application.StartupPath & "\received.jpg", OpenMode.Binary, OpenAccess.Write)
                        FilePut(1, incomingFile)
                        FileClose()
                        bm = Image.FromFile(Application.StartupPath & "\received.jpg")
                        pictTransfer.Image() = bm
                        isFileSizeFlag = True
                    End If




                    'if the file is bigger than the Integer (2^32 -1 bits)
                    'then this algorithm works instead


                    'incomingDataSize = tcpClient.Available
                    'tcpClient.Receive(incomingFile, received, tcpClient.Available, SocketFlags.None)


                    'received = received + incomingDataSize


                    '  If received = longFileSize Then


                    'FileOpen(1, Application.StartupPath & "\received.jpg", OpenMode.Binary, OpenAccess.Write)
                    'FilePut(1, incomingFile)
                    'FileClose()
                    'bm = Image.FromFile(Application.StartupPath & "\received.jpg")
                    'pictTransfer.Image() = bm
                    'isFileSizeFlag = True
                    'End If


                    End If
            End If
        End If
    End Sub


    Private Sub frmClient_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        isFileSizeFlag = True


    End Sub


    Private Sub btnRequest_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRequest.Click
        Dim conStoB As New System.Text.ASCIIEncoding
        tcpClient.Send(conStoB.GetBytes("SENDFILE", 0, Len("SENDFILE")), Len("SENDFILE"), SocketFlags.None)
        type = 0 'because it waits for a file
    End Sub
End Class


Server side
VB.NET:
Imports System.NetImports System.Net.Sockets
Public Class frmServer
    Private tcpServer As Socket
    Private flagConnected As Boolean
    Private tcpListener As TcpListener
    Private localEndpoint As IPEndPoint
   


    Private Sub frmServer_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim frmClient As New frmClient
        frmClient.Show()


        localEndpoint = New IPEndPoint(IPAddress.Any, 1001)


        tcpServer = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)


        tcpListener = New TcpListener(localEndpoint)
        tcpListener.Start()
        Timer1.Start()
        flagConnected = False




    End Sub


    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Dim incomingMessage() As Byte
        Dim conBtoS As New System.Text.ASCIIEncoding
        Dim conStoB As New System.Text.ASCIIEncoding


        If tcpListener.Pending Then
            tcpServer = tcpListener.AcceptSocket
            flagConnected = True
        End If
        If flagConnected = True Then
            If tcpServer.Connected = False Then
                tcpServer.Close()
                Timer1.Stop()
            End If
        End If


        '  If tcpServer.Available > 0 Then
        'ReDim receivedBytes(tcpServer.Available)
        '   tcpServer.Receive(receivedBytes, SocketFlags.None)
        '  txtShow.Text = txtShow.Text & "Client says: " & conBtoS.GetString(receivedBytes, 0, receivedBytes.GetLength(0))
        '   txtShow.Text = txtShow.Text & vbNewLine
        '   End If


    
        If tcpServer.Available > 0 Then
            ReDim incomingMessage(tcpServer.Available - 1)
            tcpServer.Receive(incomingMessage, tcpServer.Available, SocketFlags.None)
            If conBtoS.GetString(incomingMessage, 0, incomingMessage.Length) = "SENDFILE" Then
                FileOpen(1, Application.StartupPath & "\sendfile.jpg", OpenMode.Binary)
                tcpServer.Send(conStoB.GetBytes(Str(LOF(1)), 0, Len(Str(LOF(1)))), Len(Str(LOF(1))), SocketFlags.None)
                FileClose(1)
                MsgBox("SENT FILE SIZE")
            ElseIf conBtoS.GetString(incomingMessage, 0, incomingMessage.Length) = "OK" Then
                tcpServer.SendFile(Application.StartupPath & "\sendfile.jpg")
            Else
                txtShow.Text = txtShow.Text & "Client says: " & conBtoS.GetString(incomingMessage, 0, incomingMessage.GetLength(0))
                txtShow.Text = txtShow.Text & vbNewLine
            End If
        End If
    End Sub


    Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
        Dim sendBytes() As Byte
        Dim conStoB As New System.Text.ASCIIEncoding
        If txtSend.TextLength > 0 Then
            sendBytes = conStoB.GetBytes(txtSend.Text)
            tcpServer.Send(sendBytes, sendBytes.Length, SocketFlags.None)


            txtShow.Text = txtShow.Text & "Server says: " & txtSend.Text
            txtShow.Text = txtShow.Text & vbNewLine
            txtSend.Text = ""
        End If
    End Sub
End Class
 
I am not sure why are you using a Timer. If you want to implement a chat system then I suggest using a loop and a ManualResetEvent to manage the send and receive actions or start two separate sockets; one for receiving and one for sending simultaneously on different ports. I prefer to manage the send and receive with some kind of thread lock. I also suggest using asynchronous methods. However; for now just try to move away from the timer. A timer may be used to send a pulse or ping to continue managing a connection but even this isn't needed so much in TCP.

As far as sending or receiving an image or message you can easily use the same socket. Have the server send a message in the first section of the buffer.

Example: I have used the first 8 bytes of the buffer to send the size of the message and the 9th byte to send the type of message.

Example continued: Build an enumeration to send the type of messages and use it on both sides. Make the enum a byte (limits the messages to 255 which is plenty agreed?)

VB.NET:
Public Enum MessageTypes as Byte
     Ping
     Image
     Message
     Typing
     Idle
     Active
     Disconnect
End Enum

Now when you prepare a message to be sent add 9 extra bytes to the buffer and make sure both sides, server and clients, are programmed to insert the information into the first 9 bytes of the buffer.

Example:

VB.NET:
Dim sendBuffer(originalBuffer.Length + 9 -1) as Byte 
'I added the plus 9 and minus 1 for illustration since VB arrays’ are indexed 1 less than the actual length.

Dim x as integer = 0
For each b as Byte in BitConverter.GetBytes(originalBuffer.Length)
     sendBuffer(x) = b
     x+=1
Next x

'Now add the message to send to the recipient such as 'Image' if the message contains an image.

sendBuffer(8) = MessageTypes.Image

Then finish filling the sendBuffer with the originalBuffer either with a loop or Array.Copy.

Array.Copy(originalBuffer, 0, sendBuffer, 9, originalBuffer.Length)

'Now send the new buffer with the messages embedded.

Socket.Send(sendBuffer)

'NOW ON THE RECEIVING END READ OUT THE FIRST BUFFER AS LONG AS YOU RECEIVE AT LEAST 9 BYTES (Which you should)

Dim firstBuffer(1023) as Byte

Dim bytesReceived as Integer = Socket.Receive(firstBuffer)

Dim byteAccumulator as Integer = bytesReceived - 9

Dim messageSize as Integer = BitConverter.ToInt64(firstBuffer, 0) 'ToInt64 automatically reads 8 bytes from Index point

Dim messageType as MessageTypes = firstBuffer(8) ‘Now you know what type of message if incoming

‘Now start writing what is left of the buffer to a new buffer

Dim actualbuffer(byteAccumulator - 1) ‘Used 9 – 1 as demonstration; 9 for info part of array. -10 is fine.

Array.Copy(firstBuffer, 9, actualBuffer, 0, byteAccumulator)

‘Now continue reading array until you reach the message length

Do Until byteAccumulator = messageSize

     Dim tempBuffer(1023) as Byte

     Dim bytesReceived as Integer = Socket.Receive(tempBuffer)

     Array.Copy(tempBuffer, 0, actualBuffer, byteAccumulator, bytesReceived)
   
     byteAccumulator += bytesReceived

Loop

‘Once the message has reached the limit you use the actualBuffer according to the message type.

Select Case messageType

     Case MessageTypes.Ping
     	‘Sending a blank packet for relay
  
     Case MessageTypes.Image
	‘The actualBuffer is the buffer of an Image so run code to extract the image.

     Case MessageTypes.Message
     	‘The actualBuffer is a string message so extract the string message.

     Case Else
	‘And so on…

End Select

No need for timers or unique sockets etc. However; you need to figure a way to receive and send at the same time. This may require setting up a socket for sending and a separate one for sending or queuing the different actions. A ManualResetEvent will help achieve this easily.

This code is presented as an idea to maintain simplicity. Obviously it isn’t continuous or all in one location. The logic is the only thing being demonstrated. I recommend Asynchronous methods and error handling techniques.

Does this help or make since?
 
Last edited:
Back
Top