Отправка и получение данные по сети с использованием TcpClient

Мне нужно разработать сервис, который будет подключаться к TCP-серверу. Основными задачами являются чтение входящих сообщений, а также отправка команд на сервер в течение десяти минут, как команда синхронизации. Например, я использовал объект TcpClient, как показано ниже:

...
TcpClient tcpClient = new TcpClient();
tcpClient.Connect("x.x.x.x", 9999);
networkStream = tcpClient.GetStream();
clientStreamReader = new StreamReader(networkStream);
clientStreamWriter = new  StreamWriter(networkStream);
while(true)
{
   clientStreamReader.Read()
}

Кроме того, когда мне нужно записать что-либо в любом методе, я использую:

 clientStreamWriter.write("xxx");

Правильно ли это использование? Или есть лучший способ?

35
задан Peter Mortensen 27 July 2013 в 19:47
поделиться

2 ответа

Во-первых, я рекомендую использовать WCF, .NET Remoting или какую-либо другую коммуникационную абстракцию более высокого уровня. Кривая обучения для «простых» сокетов почти такая же высокая, как и для WCF, потому что при непосредственном использовании TCP/IP существует множество неочевидных ловушек.

Если вы решите продолжить путь TCP/IP, просмотрите мой .NET TCP/IP FAQ, особенно разделы, посвященные фреймам сообщений и спецификациям протоколов приложений. .

Кроме того, используйте API асинхронных сокетов. Синхронные API-интерфейсы не масштабируются и в некоторых ситуациях могут привести к взаимоблокировкам. Синхронные API-интерфейсы позволяют создать довольно небольшой пример кода, но в реальном коде производственного качества используются асинхронные API-интерфейсы.

21
ответ дан 27 November 2019 в 07:09
поделиться

Мне повезло с использованием объекта сокета напрямую (а не через TCP-клиент). Я создаю объект Server, который выглядит примерно так (для краткости я отредактировал некоторые вещи, такие как обработка исключений, но я надеюсь, что эта идея будет понятна.)...

public class Server()
{
    private Socket sock;
    // You'll probably want to initialize the port and address in the
    // constructor, or via accessors, but to start your server listening
    // on port 8080 and on any IP address available on the machine...
    private int port = 8080;
    private IPAddress addr = IPAddress.Any;

    // This is the method that starts the server listening.
    public void Start()
    {
        // Create the new socket on which we'll be listening.
        this.sock = new Socket(
            addr.AddressFamily,
            SocketType.Stream,
            ProtocolType.Tcp);
        // Bind the socket to the address and port.
        sock.Bind(new IPEndPoint(this.addr, this.port));
        // Start listening.
        this.sock.Listen(this.backlog);
        // Set up the callback to be notified when somebody requests
        // a new connection.
        this.sock.BeginAccept(this.OnConnectRequest, sock);
    }

    // This is the method that is called when the socket recives a request
    // for a new connection.
    private void OnConnectRequest(IAsyncResult result)
    {
        // Get the socket (which should be this listener's socket) from
        // the argument.
        Socket sock = (Socket)result.AsyncState;
        // Create a new client connection, using the primary socket to
        // spawn a new socket.
        Connection newConn = new Connection(sock.EndAccept(result));
        // Tell the listener socket to start listening again.
        sock.BeginAccept(this.OnConnectRequest, sock);
    }
}

Затем я использую отдельный класс Connection для управлять индивидуальным соединением с удаленным хостом. Это выглядит примерно так...

public class Connection()
{
    private Socket sock;
    // Pick whatever encoding works best for you.  Just make sure the remote 
    // host is using the same encoding.
    private Encoding encoding = Encoding.UTF8;

    public Connection(Socket s)
    {
        this.sock = s;
        // Start listening for incoming data.  (If you want a multi-
        // threaded service, you can start this method up in a separate
        // thread.)
        this.BeginReceive();
    }

    // Call this method to set this connection's socket up to receive data.
    private void BeginReceive()
    {
        this.sock.BeginReceive(
                this.dataRcvBuf, 0,
                this.dataRcvBuf.Length,
                SocketFlags.None,
                new AsyncCallback(this.OnBytesReceived),
                this);
    }

    // This is the method that is called whenever the socket receives
    // incoming bytes.
    protected void OnBytesReceived(IAsyncResult result)
    {
        // End the data receiving that the socket has done and get
        // the number of bytes read.
        int nBytesRec = this.sock.EndReceive(result);
        // If no bytes were received, the connection is closed (at
        // least as far as we're concerned).
        if (nBytesRec <= 0)
        {
            this.sock.Close();
            return;
        }
        // Convert the data we have to a string.
        string strReceived = this.encoding.GetString(
            this.dataRcvBuf, 0, nBytesRec);

        // ...Now, do whatever works best with the string data.
        // You could, for example, look at each character in the string
        // one-at-a-time and check for characters like the "end of text"
        // character ('\u0003') from a client indicating that they've finished
        // sending the current message.  It's totally up to you how you want
        // the protocol to work.

        // Whenever you decide the connection should be closed, call 
        // sock.Close() and don't call sock.BeginReceive() again.  But as long 
        // as you want to keep processing incoming data...

        // Set up again to get the next chunk of data.
        this.sock.BeginReceive(
            this.dataRcvBuf, 0,
            this.dataRcvBuf.Length,
            SocketFlags.None,
            new AsyncCallback(this.OnBytesReceived),
            this);

    }
}

Вы можете использовать свой объект Connection для отправки данных, напрямую вызывая его Socket, например так...

this.sock.Send(this.encoding.GetBytes("Hello to you, remote host."));

Как я уже сказал, я попытался отредактировать код здесь для публикации, поэтому прошу прощения, если в нем есть какие-либо ошибки.

12
ответ дан 27 November 2019 в 07:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: