Simple One Thread Socket - TCP Server

笑着哭i 提交于 2020-12-04 05:16:50

问题


First, I don't know if Stackoverflow is the best site to post this kind of message, but I don't know another sites like this.

In oder to understand properly tcp programmation in C#, I decided to do all possible ways from scratch. Here is what I want to know (not in the right order: - Simple One Thread Socket Server (this article) - Simple Multiple Threads Socket Server (I don't know how, cause threads are complicated) - Simple Thread Socket Server (put the client management in another thread) - Multiple Threads Socket Server - Using tcpListener - Using async / Await - Using tasks The ultimate objective is to know how to do the best tcp server, without just copy/paste some parts of come, but understand properly all things.

So, this is my first part : a single thread tcp server.

There is my code, but I don't think anybody will correct something, because it's quite a copy from MSDN : http://msdn.microsoft.com/en-us/library/6y0e13d3(v=vs.110).aspx

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace SimpleOneThreadSocket
{
    public class ServerSocket
    {
        private int _iPport = -1;
        private static int BUFFER_SIZE = 1024;
        private Socket _listener = null;

        public ServerSocket(int iPort)
        {            
            // Create a TCP/IP socket.
            this._listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            // Save the port
            this._iPport = iPort;
        }

        public void Start()
        {
            byte[] buffer = null;
            String sDatasReceived = null;

            // Bind the socket to loopback address
            try
            {
                this._listener.Bind(new System.Net.IPEndPoint(System.Net.IPAddress.Loopback, _iPport));
                this._listener.Listen(2);
            }
            catch (Exception e)
            {
                System.Console.WriteLine(e.ToString());
            }

            // Listening
            try
            {
                Console.WriteLine("Server listening on 127.0.0.1:" + _iPport);

                while (true)
                {
                    Socket client = this._listener.Accept();
                    Console.WriteLine("Incoming connection from : " + IPAddress.Parse(((IPEndPoint)client.RemoteEndPoint).Address.ToString()) + ":" + ((IPEndPoint)client.RemoteEndPoint).Port.ToString());

                    // An incoming connection needs to be processed.
                    while (true)
                    {
                        buffer = new byte[BUFFER_SIZE];
                        int bytesRec = client.Receive(buffer);
                        sDatasReceived += Encoding.ASCII.GetString(buffer, 0, bytesRec);
                        if (sDatasReceived.IndexOf("<EOF>") > -1)
                        {
                            // Show the data on the console.
                            Console.WriteLine("Text received : {0}", sDatasReceived);

                            // Echo the data back to the client.
                            byte[] msg = Encoding.ASCII.GetBytes(sDatasReceived);

                            client.Send(msg);

                            sDatasReceived = "";
                            buffer = null;
                        }
                        else if (sDatasReceived.IndexOf("exit") > -1)
                        {
                            client.Shutdown(SocketShutdown.Both);
                            client.Close();

                            sDatasReceived = "";
                            buffer = null;

                            break;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
    }
}

But I have some questions about that :

  • Listen Method from Socket have a parameter : backlog. According to MSDN, backlog is the number of available connection. I don't know why, when I put 0, I can connect to my server with multiple Telnet sessions. EDIT : 0 & 1 both allow 2 connections (1 current, 1 pending), 2 allow 3 connections (1 current, 2 pending), etc... So I didn't understand well the meaning of MSDN.

  • Can you confirm that Accept Method will take each connection one after one, that's why I see text from differents Telnet session in my server ?

  • Can you confirm (my server is a C# library) I can't kill my server (with this kind of code) without killing the process ? It could be possible with threads but it will come later.

If something is wrong in my code, please help me :)

I will come back soon with a simple multiple thread socket server, but I don't know how (I think one step is available before using threads or async/await).


回答1:


First off, do your best not to even learn this. If you can possibly use a SignalR server, then do so. There is no such thing as a "simple" socket server at the TCP/IP level.

If you insist on the painful route (i.e., learning proper TCP/IP server design), then there's a lot to learn. First, the MSDN examples are notoriously bad starting points; they barely work and tend to not handle any kind of error conditions, which is absolutely necessary in the real world when working at the TCP/IP level. Think of them as examples of how to call the methods, not examples of socket clients or servers.

I have a TCP/IP FAQ that may help you, including a description of the backlog parameter. This is how many connections the OS will accept on your behalf before your code gets around to accepting them, and it's only a hint anyway.

To answer your other questions: A single call to Accept will accept a single new socket connection. The code as-written has an infinite loop, so it will work like any other infinite loop; it will continue executing until it encounters an exception or its thread is aborted (which happens on process shutdown).

If something is wrong in my code, please help me

Oh, yes. There are lots of things wrong with this code. It's an MSDN socket example, after all. :) Off the top of my head:

  1. The buffer size is an arbitrary value, rather low. I would start at 8K myself, so it's possible to get a full Ethernet packet in a single read.
  2. The Bind explicitly uses the loopback address. OK for playing around, I guess, but remember to set this to IPAddress.Any in the real world.
  3. backlog parameter is OK for testing, but should be int.MaxValue on a true server to enable the dynamic backlog in modern server OSes.
  4. Code will fall through the first catch and attempt to Accept after a Bind/Listen failed.
  5. If any exception occurs (e.g., from Listen or Receive), then the entire server shuts down. Note that a client socket being terminated will result in an exception that should be logged/ignored, but it would stop this server.
  6. The read buffer is re-allocated on each time through the loop, even though the old buffer is never used again.
  7. ASCII is a lossy encoding.
  8. If a client cleanly shuts down without sending <EOF>, then the server enters an infinite busy loop.
  9. Received data is not properly separated into messages; it is possible that the echoed message contains all of one message and part of another. In this particular example it doesn't matter (since it's just an echo server and it's using ASCII instead of a real encoding), but this example hides the fact that you need to handle message framing properly in any real-world application.
  10. The decoding should be done after the message framing. This isn't necessary for ASCII (a lossy encoding), but it's required for any real encodings like UTF8.
  11. Since the server is only either receiving or sending at any time (and never both), it cannot detect or recover from a half-open socket situation. A half-open socket will cause this server to hang.
  12. The server is only capable of a single connection at a time.

That was just after a brief readthrough. There could easily be more.



来源:https://stackoverflow.com/questions/25248704/simple-one-thread-socket-tcp-server

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!