Skip to content
This repository has been archived by the owner on Jun 12, 2020. It is now read-only.

Add TCP protocol support to Socket #59

Merged
merged 18 commits into from
Apr 28, 2016
Merged

Conversation

pekiZG
Copy link
Contributor

@pekiZG pekiZG commented Apr 13, 2016

Added TCP protocol parameter switch.
Name refactoring.

Added TCP protocol parameter switch.
Name refactoring.
@pekiZG pekiZG mentioned this pull request Apr 13, 2016
@DarrellMozingo
Copy link
Collaborator

Thanks for the PR Petar! A few concerns:

  1. The project .NET version being upgraded is a breaking change we weren't ready to make yet. What forced you to do it?
  2. No smoke/acceptance tests for the TCP functionality itself
  3. I don't see the TCP connection being opened anywhere? According to the docs for SendTo(), it should be throwing an exception:

If you are using a connection-oriented protocol, you must first establish a remote host connection by calling the Connect method or accept an incoming connection request using the Accept method. If you do not establish or accept a remote host connection, SendTo will throw a SocketException.

The management of a TCP connection is why I was hesitant to add this functionality in the first place. I can't see a full handshake being done before each send request since it's all blocking and would kill the calling app. It's all fully possible of course, just more than I wanted to add for something I still don't see a huge amount of benefit from :)

@pekiZG
Copy link
Contributor Author

pekiZG commented Apr 18, 2016

Hi Darrell,
This is my first PR :)

I would like to address all your concerns.

  1. Break was not intentional. Visual Studio 2015 on Windows 10 wouldn't open it.
    Later I found how to enable .net 2.0+ and will migrate it without breaking.
  2. Still looking why tests won't run. It's probably connected to bullet number 1.
  3. I tried it and it didn't throw an exception. SendTo() should be used on line 107 in StatsdUDP.cs
    I'm not happy how I did it.

@pekiZG
Copy link
Contributor Author

pekiZG commented Apr 18, 2016

@DarrellMozingo

I have successfully run all the tests after poking around and finding out that NUnit 2.6 is being used.
Will have TCP connection test soon.

KR
Petar

Changed to implementation towards the Interface.
Added StatsdTCP concrete class.
Reverted StatsdUDP to original state.
@pekiZG
Copy link
Contributor Author

pekiZG commented Apr 19, 2016

After finding out that there is App.confing in Tests I have created Hyper-V and configured InfluxDB with Chronograph and Telegraph to have valid Smoke tests. (See picture below)

image

TCP Smoke test is passing.

I have changed to the implementation towards the interface over concrete type.
You can see it in the last commit (src/StatsdClient/Metrics.cs)

Also, I'm not done yet.

Thinking about doing it with async methods. @DarrellMozingo that should address your concern on blocking the calling app. Right?

@DarrellMozingo
Copy link
Collaborator

Thanks for fixing the .NET version and splitting out the TCP/UDP classes - nice touch.

I see you're doing the connect/disconnect now. I think that should be in a try/finally so ensure the connection is closed if something goes wrong in the send (I'll add an in-line comment). Also a base class (or a separate class) to handle the IP address resolution as it's a bit convoluted?

I've personally always been against doing the TCP for socket management and the speed hit of doing a sync call. If it's an absolute requirement, I feel it's better to split that responsibility out to another app (ie have a statsd relay running on each server that you'd send UDP stats to, and it would relay them in TCP). Do you still think the feature is needed if someone does this?

Thanks again for taking the time to contribute, I do appreciate it! :)

{
_clientSocket.Connect(IPEndpoint.Address, _port);
_clientSocket.SendTo(encodedCommand, encodedCommand.Length, SocketFlags.None, IPEndpoint);
_clientSocket.Disconnect(false);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put this in a try {} finally {} so we're not leaving hanging TCP connections?

@pekiZG
Copy link
Contributor Author

pekiZG commented Apr 21, 2016

@DarrellMozingo no problem I really want to contribute.
Also, I will do a little How to setup development environment. Recently had to do a clean install and it took me time to setup.

My position is that you should have a choice between UDP and TCP.
If someone has control over the network and can place another app. that sounds like a better option.

Today I will work on this part from documentation.
https://msdn.microsoft.com/en-us/library/system.net.sockets.socket(v=vs.80).aspx

To process communications using separate threads during execution, use the following methods, which are designed for asynchronous operation mode

Using BeginSend and EndSend would be much better.
I will try to make some kind of load test. Have no idea how (actually I have).
Have to think about what I want to measure.

On the topic of IP address resolution, that should definitely be pulled out (separation of concern).

I really appreciate you taking time to look at my messy code :)
Pair programming 👍

Pulled out shared interface into separate file.
Pulled out address resolution.
{
_clientSocket.Connect(IPEndpoint);
_clientSocket.SendTo(encodedCommand, encodedCommand.Length, SocketFlags.None, IPEndpoint);
_clientSocket.Disconnect(false);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Disconnect() should be in the finally block, no?

Copy link
Contributor Author

@pekiZG pekiZG Apr 22, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes,

still working on this part to make it Async. :)

@DarrellMozingo
Copy link
Collaborator

I'm still hesitant to add it, but I suppose the TCP code will be insulated in a separate class and not defaulted or anything, so we can allow it with perhaps appropriate warnings (ie to use UDP or a TCP relay app first).

Thanks for the fixes so far! I'll be away for a few days, so if you get anything else done I'll take a look next week.

@pekiZG
Copy link
Contributor Author

pekiZG commented Apr 25, 2016

I haven't had time over the weekend.
I will have it finished tonight \o/

}
finally
{
_clientSocket.Disconnect(false);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed Disconnect() in favor of Shutdown() and Close()

@pekiZG
Copy link
Contributor Author

pekiZG commented Apr 25, 2016

@DarrellMozingo I think I'm done. \o/
Need second opinion.

@DarrellMozingo
Copy link
Collaborator

Nice work!

I know IDisposable was already on the UDP version, but seeing it do nothing in the TCP one and not really being called anywhere in the UDP version makes me wonder if it's even needed?

Also can you rename the TCP smoke test to match the class/other UDP one?

@pekiZG
Copy link
Contributor Author

pekiZG commented Apr 27, 2016

Hi @DarrellMozingo

I have implemented IDisposable interface, and renamed filenames to reflect classnames.
I didn't catch what you mean to rename smoketests?

Is there some convention I'm not being aware of?

also, I'm logging to console?
Do you think that's a smart thing to do? Or just to "swallow" the error?

@DarrellMozingo
Copy link
Collaborator

Yea, saw you implmented IDisposable. I was wondering if it could be removed all together? I don't see Dispose() being called on the UDP version. Maybe it's best to just close the UDP socket inside the Send() method as well...

Ignore my smoke test naming comment. I misread something and thought the UDP test was named differently. It's fine as is.

Swallowing seems wrong. I think something like TraceSource (built into .NET) or LibLog would be best, but we're not doing either now and there hasn't been a need yet. The console log seems good enough for now anyway :)

@DarrellMozingo
Copy link
Collaborator

The build for this branch is broken. Not sure why the PR didn't update (I just enabled it, maybe I did it wrong!).

Looks like the project file still has StatsdTCP.cs instead of StatsdTCPClient.cs (same for UDP as well)?

@pekiZG
Copy link
Contributor Author

pekiZG commented Apr 28, 2016

well, thinking is that if you close the outside connection (finally block), you shouldn't worry about dispose.

Or if you are doing something like this:
https://msdn.microsoft.com/en-us/library/yh598w02(v=vs.140).aspx

using(mySocket)
{
// do work
}

Dispose will be properly called.


Yes, I changed the names; Didn't know what you were referencing on SmokeTest

I can change it back?

@pekiZG
Copy link
Contributor Author

pekiZG commented Apr 28, 2016

Yes, you are right... I will fix it now :)

@DarrellMozingo
Copy link
Collaborator

Regarding disposable, you're absolutely correct. No body is doing a using() with it though, and you're disposing the socket right away in the TCP class. Perhaps we should do the same with the UDP one then remove the IDisposable interface entirely? It would not be doing anything then.

I changed the filenames, but forgot to push changed .csproj
@pekiZG
Copy link
Contributor Author

pekiZG commented Apr 28, 2016

Here is what happened.
Didn't push the changed StatsdClient.csproj

Please check if it's passing now (It should).

https://ci.appveyor.com/project/DarrellMozingo/statsd-csharp-client

EDIT:
I think smoke test will fail

@pekiZG
Copy link
Contributor Author

pekiZG commented Apr 28, 2016

Yes, TCP smoke test will fail.
UDP will not because it's not waiting on connection.

I should change the smoke test to use TcpListener

@pekiZG
Copy link
Contributor Author

pekiZG commented Apr 28, 2016

@DarrellMozingo
Copy link
Collaborator

I like the idea of the smoke test spinning up a simple TcpListener to receive the connection. As a bonus it can read the data and make sure it's correct :)

@pekiZG
Copy link
Contributor Author

pekiZG commented Apr 28, 2016

I was under Impression that Smoke test should be done on 'real' thing :)

That's why I did all this

EDIT:
Will fix it now so the test passes :)

@DarrellMozingo
Copy link
Collaborator

You're correct, it should be hitting the real system. From the point of view of the client though I can see just making sure it's sending a properly formed TCP packet, rather than a full end-to-end test that makes sure it shows up in the back-end correctly. So just spinning up a TCP socket to send to should work well enough for our purposes.

It should now pass the CI build on AppVeyor
@pekiZG
Copy link
Contributor Author

pekiZG commented Apr 28, 2016

@DarrellMozingo 1.2.40 built successfully

https://ci.appveyor.com/project/DarrellMozingo/statsd-csharp-client/build/1.2.40

We should probably update the readme.md 👍

System.Net.IPAddress localAddr = System.Net.IPAddress.Parse(_serverName);

// TcpListener server = new TcpListener(port);
server = new TcpListener(localAddr, port);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you wrap this in a using{} to make sure it's always stopped?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TcpListener class doesn't inherit/implement IDisposable Interface.
For that reason It's can't be wrapped in using()

If you try you get Type used in a using statement must be implicitly convertible to 'System.IDisposable'

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quite right :) I was thinking of TcpClient, sorry. Maybe just put the Stop() in a finally block, or probably a test teardown fixture would be better. Just want to make sure if the test fails that listening socket gets closed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went with setup/teardown fixture :)

@DarrellMozingo
Copy link
Collaborator

Looks good, thanks! Want to take a stab at updating the README?

@pekiZG
Copy link
Contributor Author

pekiZG commented Apr 28, 2016

Sure,

I would love to :)

@pekiZG
Copy link
Contributor Author

pekiZG commented Apr 28, 2016

@DarrellMozingo readme is updated :)

The changelog is left up to you 👍

@DarrellMozingo DarrellMozingo merged commit f87a98c into Pereingo:master Apr 28, 2016
@DarrellMozingo
Copy link
Collaborator

Great, thanks a lot for the contribution Petar! I'll get it pushed out today or tomorrow.

@pekiZG
Copy link
Contributor Author

pekiZG commented Apr 28, 2016

No hurry :)

I'm here if additional tweaks are needed.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants