nested enum for supported states
public enum status
listening
connected
end enum status
start up the talkers functionality
public sub start()
threadpool.queueuserworkitem(new system.threading.waitcallback(addressof establishsocket))
end sub start
establish a socket connection and start receiving
private sub establishsocket(byval state as object)
try
if not client, setup listner
if not client then
dim listener as socket
try
listener = new socket(addressfamily.internetwork, sockettype.stream, protocoltype.tcp)
listener.blocking = true
listener.bind(endpoint)
setstatus(status.listening)
listener.listen(0)
socket = listener.accept()
listener.close()
catch e as socketexception
if there is already a listener on this port try client
if e.errorcode = 10048 then
client = true
endpoint = new ipendpoint(dns.resolve("127.0.0.1").addresslist(0), endpoint.port)
else
raiseevent notifications(notification.errornotify, "error initializing socket:" & controlchars.crlf & e.tostring())
end if
end try
end if
try a client connection
if client then
dim temp as new socket(addressfamily.internetwork, sockettype.stream, protocoltype.tcp)
temp.blocking = true
temp.connect(endpoint)
socket = temp
end if
if it all worked out, create stream objects
if not (socket is nothing) then
setstatus(status.connected)
dim stream as new networkstream(socket)
reader = new streamreader(stream)
writer = new streamwriter(stream)
raiseevent notifications(notification.initialized, me)
else
raiseevent notifications(notification.errornotify, "failed to establish socket")
end if
start receiving talk
note: on w2k and later platforms, the networkstream.read()
method called in receivetalke will generate an exception when
the remote connection closes. we handle this case in our
catch block below.
receivetalk()
on win9x platforms, networkstream.read() returns 0 when
the remote connection closes, prompting a graceful return
from receivetalk() above. we will generate a notification.end
message here to handle the case and shut down the remaining
wintalk instance.
raiseevent notifications(notification.endnotify, "remote connection has closed.")
catch e as ioexception
dim sockexcept as socketexception = ctype(e.innerexception, socketexception)
if not (sockexcept is nothing) and 10054 = sockexcept.errorcode then
raiseevent notifications(notification.endnotify, "remote connection has closed.")
else
raiseevent notifications(notification.errornotify, "socket error:" & controlchars.crlf & e.message)
end if
catch e as exception
raiseevent notifications(notification.errornotify, "socket error:" & controlchars.crlf & e.message)
end try
end sub establishsocket
send text to remote connection
public sub sendtalk(byval newtext as string)
dim send as string
is this an append
if prevsendtext.length <= newtext.length and string.compareordinal(newtext, 0, prevsendtext, 0, prevsendtext.length) = 0 then
dim append as [string] = newtext.substring(prevsendtext.length)
send = string.format("a{0}:{1}", append.length, append)
or a complete replacement
else
send = string.format("r{0}:{1}", newtext.length, newtext)
end if
send the data and flush it out
writer.write(send)
writer.flush()
save the text for future comparison
prevsendtext = newtext
end sub sendtalk
send a status notification
private sub setstatus(byval statusobj as status)
me.statusobj = statusobj
raiseevent notifications(notification.statuschange, statusobj)
end sub setstatus
receive chat from remote client
private sub receivetalk()
dim commandbuffer(19) as char
dim onebuffer(0) as char
dim readmode as integer = 1
dim counter as integer = 0
dim textobj as new stringbuilder()
while readmode <> 0
if reader.read(onebuffer, 0, 1) = 0 then
readmode = 0
goto continuewhile1
end if
select case readmode
case 1
if counter = commandbuffer.length then
readmode = 0
goto continuewhile1
end if
if onebuffer(0) <> ":"c then
commandbuffer(counter) = onebuffer(0)
counter = counter + 1
else
counter = convert.toint32(new string(commandbuffer, 1, counter – 1))
if counter > 0 then
readmode = 2
textobj.length = 0
else
if commandbuffer(0) = "r"c then
counter = 0
prevreceivetext = string.empty
raiseevent notifications(notification.received, prevreceivetext)
end if
end if
end if
case 2
textobj.append(onebuffer(0))
counter = counter – 1
if counter = 0 then
select case commandbuffer(0)
case "r"c
prevreceivetext = textobj.tostring()
case else
prevreceivetext += textobj.tostring()
end select
readmode = 1
raiseevent notifications(notification.received, prevreceivetext)
end if
case else
readmode = 0
goto continuewhile1
end select
continuewhile1:
end while
end sub receivetalk
private socket as socket
private reader as textreader
private writer as textwriter
private client as boolean
private endpoint as ipendpoint
private prevsendtext as string
private prevreceivetext as string
private statustext as string
private statusobj as status
end class talker
