TcpLink
An Internet TCP/IP connection.
Properties
- ELinkState LinkState
- LinkState is only valid for TcpLink at this time.
- IpAddr RemoteAddr
- Contains address of peer connected to from a Listen().
(The IpAddr struct is declared in the InternetLink class.) - class<TcpLink> AcceptClass
- If AcceptClass is not None, an Actor of class AcceptClass will be spawned when an incoming connecting is accepted, leaving the listener open to accept more connections. Accepted() is called only in the child class. You can use the LostChild() and GainedChild() events (declared in the Actor class) to track your children.
- const Array<byte> SendFIFO
- This is a dynamic array. It is not accessible in the version of UnrealScript that comes with v436 of the Unreal Engine.
ELinkState enum
- STATE_Initialized
- Sockets is initialized
- STATE_Ready
- Port bound, ready for activity
- STATE_Listening
- Listening for connections
- STATE_Connecting
- Attempting to connect
- STATE_Connected
- Open and connected
- STATE_ListenClosePending
- Socket in process of closing
- STATE_ConnectClosePending
- Socket in process of closing
- STATE_ListenClosing
- Socket in process of closing
- STATE_ConnectClosing
- Socket in process of closing
Methods
Native function
- native function int BindPort (optional int Port, optional bool bUseNextAvailable)
- Binds a free port or optional port specified in argument one.
- native function bool Listen ( )
- Listen for connections. Can handle up to 5 simultaneous connections. Returns false if failed to place socket in listen mode.
- native function bool Open (IpAddr Addr)
- Open a connection to a foreign host.
- native function bool Close ( )
- Closes the current connection.
- native function bool IsConnected ( )
- Returns true if connected.
- native function int SendText (coerce string Str)
- Sends text string. Appends a CR/LF if LinkMode=MODE_Line. Returns number of bytes sent.
- native function int SendBinary (int Count, byte B[255])
- Send data as a byte array.
- native function int ReadText (out string Str)
- Reads pending data as a text string. (RMODE_Manual) Returns number of bytes read.
- native function int ReadBinary (int Count, out byte B[255])
- Read pending data as a byte array. (RMODE_Manual). Returns the actual count (i.e. amound of valid bytes in the array).
Events
Note that ReceivedBinary is only called once per frame which will tie the amount of data you can read to the frame rate. In cases where your receiving several kilobytes you can manually receive pending data within a loop in Tick. However while reading this data the rest of the game will be stopped until you're done.
ReceivedText and ReceivedLine are also called once per frame, but should not require this technique as they get as much data as possible.
- event Accepted ( )
- Called during STATE_Listening when a new connection is accepted.
- event Opened ( )
- Called when socket successfully connects.
- event Closed ( )
- Called when Close() completes or the connection is dropped.
- event ReceivedText (string Text)
- Called when data is received and connection mode is MODE_Text.
- event ReceivedLine (string Line)
- Called when data is received and connection mode is MODE_Line. However, this is broken, though not as bad as receivedbinary. It won't actually break it into lines at all. It is simply a normal receivedtext...
- event ReceivedBinary (int Count, byte B[255])
- Called when data is received and connection mode is MODE_Binary. WARNING: In the latest released ipdrv, this function is broken. It simply will repeat the same (and incorrect) byte array constantly, with a Count that is greater than 255 (often 999). From UT2003 build 2175 this event works as it should.
Samples
Known subclasses
- UBrowserBufferedTCPLink?
- WebConnection
- WebServer
Comments
Lev: Only just started using this but i've found that if you try to connect to a server and the port your connecting to is not listening (i.e. the service your requesting is not running) then the tcplink will just sit in the STATE_Connecting state. I tried a work around for this by trying to timeout and close the link after a number of seconds but all this produces is "Close: Error while attempting to close socket." in the log files, which makes sense as the connection is not open yet. Anyone else know if this problem is my own code or a problem in the class?
Edit: Just checked the parent class InternetLink and found that the GetLastError() returns error code 10057 which is the winsock error for socket not connected.
El Muerte TDS: you just have to wait for the TCP connection time out, I think this is set to 300 seconds. This is normal behaviour and shouldn't be changed.
Lev: I can only speak from experience but every tcp client I’ve encountered will immediately come back with "connection failed" or "connection refused" when the service you’re requesting is not running. It's not like it is taking a long time to connect, the server you’re trying to connect to is not running and tcp knows this. UT2K3 show this behaviour itself when you try to connect to a server that isn't running, you get a connection failed message after a few seconds.
El Muerte TDS: that behavior depends on the remote host, when packets are just dropped it will take the TCP connection timeout. Otherwise when you receive a connection refused connecting will stop.
Lev: this is the problem i am having, when a connection refused is recieved the TCPLink object state stays in STATE_Connecting. The way i am getting round it now is to take the same approach as the IRC code and introduce a manual timeout that will destroy the object when it hasn't connected by a certain timeout period.
Foxpaw: Is that bit about polling in Tick to retrieve available data at a rate faster than the frame rate an issue? Isn't the network sufficiently slow in comparison to the framerate that this would not be an issue, or am I mistaken?
Pingz: Not always... my cable connection can download 300K per second peak. Even if your doing 100fps that's still 3K per frame. Since you can't get more than 255 bytes per ReceivedBinary event your accumulating several K of data per frame. In most cases this isn't an issue, but i'm reading megabytes worth of binary data. Before it was taking minutes to get it all, but with this change i can get it all in seconds without noticeable change in my framerate. I thought it was UScript performance, but clearly it was not. After thinking for so long that it was impossible to fix and realizing my dumb mistake I thought it was important to point out the obvious fact that these events are only called once per tick.
Jimboh: Hmm...so how does unreal manage all the data being sent through? I mean, is all the data streaming in buffered into an array, and then incrementally returned when ReadBinary(int Count, out byte B[255]) is called? (this is assuming that RMODE_Manual) If thats the case, then if I was sending MB's worth of binary data to the TcpLink, then wouldn't the memory become overbloated with data? And shouldn't there be a way to erase all the data in the buffer (since MB's worth of data would take alot of time to get simply by grabbing the data 255 bytes at a time...) Anyone?
Tarquin: Is this UT or 2k4?
Jimboh: UT2004, but should it matter?
El Muerte: The OS does the buffering of the data, not the engine.
Jimboh: I see. Ok, so I went through IpDrv.dll's dependency and one of it's main dependency is WSOCK32.DLL, so I'm guessing that UT2004 uses winsock API to do it's network connectivity. Hmm...I'll look into the API and see what I can dig up. Thanks for the tip
El Muerte: ofcourse it uses WinSock on Windows. It's not like you have a choice.
Jimboh: There's always DirectPlay - for all those diehard MSFT programmers...and then theres the option of coding your own IP stack
El Muerte: DirectPlay is also WinSock. And you can't do your own IP stack, it means writing drivers.