Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Помогите с TCP сервером(постоянный коннект)

17K
13 декабря 2006 года
Mikeprosoft
15 / / 14.10.2006
Чего не хватает для того, чтобы было постоянное подключение клиента к серверу, и чтобы могли подсоединяться новые клиенты.

Код кнопки для включения сервера:
 
Код:
public void button1_Click(object sender, EventArgs e)
        {
            Thread t = new Thread(new ThreadStart(ThStart));
            t.Start();
        }

Код самого сервера:
Код:
private void ThStart()
        {
        while (true)
            {
                TcpListener TList = new TcpListener(80);
                TList.Start();            
                TcpClient TClient = TList.AcceptTcpClient();
                NetworkStream ns = TClient.GetStream();

                StreamReader srrr = new StreamReader(ns);
                StreamWriter swww = new StreamWriter(ns);
                swww.WriteLine("ПРЕВЕД");
                swww.Flush();
                swww.Close();
                srrr.Close();
                TClient.Close();
                TList.Stop();
             }
        }
713
13 декабря 2006 года
Ap0k
360 / / 13.03.2006
Код:
TcpListener listener;
public void button1_Click(object sender, EventArgs e)
{
    listener = new TcpListener(80);
    listener.Start();
    listener.BeginAcceptTcpClient(new AsyncCallback(ClientReceivedCallback), null);
}

private void ClientReceivedCallback(IAsyncResult asyncResult)
{
    try
    {
       TcpClient client = listener.EndAcceptTcpClient(asyncResult);
       listener.BeginAcceptTcpClient(new AsyncCallback(ClientReceivedCallback), null);
       NetworkStream stream = client.GetStream();
       //------твой чих-пых код, делающий непонятно что :)
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}
17K
14 декабря 2006 года
Mikeprosoft
15 / / 14.10.2006
А как мне тогда теперь идентифицировать клиентов? Т.е. как определяит, что кто-то подключился и как именно ему отправлять нужные сообщения?
713
14 декабря 2006 года
Ap0k
360 / / 13.03.2006
ClientReceivedCallback выполнится для каждого клиента в контексте отдельного потока, исходя из этого для каждого подключившегося клиента будет создан отдельный экземпляр класса TcpClient.
17K
14 декабря 2006 года
Mikeprosoft
15 / / 14.10.2006
А можно как-нибудь все-таки это сделать на тридах, и чтобы не было асинхронного вызова?
303
15 декабря 2006 года
makbeth
1.0K / / 25.11.2004
Цитата:
А можно как-нибудь все-таки это сделать на тридах, и чтобы не было асинхронного вызова?


Ответ уже был дан:

Цитата:
ClientReceivedCallback выполнится для каждого клиента в контексте отдельного потока


Смысл асинхронного вызова, то что он выполняется в отдельном потоке.

5
15 декабря 2006 года
hardcase
4.5K / / 09.08.2005
Цитата: Mikeprosoft
Чего не хватает для того, чтобы было постоянное подключение клиента к серверу, и чтобы могли подсоединяться новые клиенты.

Чем не устраивает модель ремоутинга? Тогда вообще не нужно работать с TcpClient'ами и подключение клиентов идёт полностью прозрачно.
Ты создаёшь объект, наслебуя его от MarshalByRefObject, определяя для него интерфейс I.
Далее "публикуешь" его используя RemotingConfiguration.RegisterWellKnownServiceType, предварительно создав Tcp канал TcpServerChannel. Клиенты будут соединяться автоматически через TcpClientChannel и будут работать с сервером через интерфейс I, который они получат через активатор Activator. Таким образом ты общаешься с сервером в терминах "вызов/возврат" а маршаллингом/демаршаллингом параметров и результатов занимается сам .NET.


Ключевые слова поиска в МСДН: TcpServerChannel, TcpClientChannel (там есть пример реализации, он занимает 10-20 строк)

17K
15 декабря 2006 года
Mikeprosoft
15 / / 14.10.2006
Мне надо, чтобы клиент обменивался с сервером простыми строками, сервер с ним аналогично. Всё дело в том, что аналогичную систему делают на Java, и нужно совмещение сервера на С# и клиента на Java.
Также нужно, чтобы при определенном запросе клиента(посылки определенной строки), сервер ставил его у себя в очередь, а по прошествии определенного времени, отвечал(т.о. нужно клиенты идентифицировать)
5
15 декабря 2006 года
hardcase
4.5K / / 09.08.2005
Цитата: Mikeprosoft
Мне надо, чтобы клиент обменивался с сервером простыми строками, сервер с ним аналогично. Всё дело в том, что аналогичную систему делают на Java, и нужно совмещение сервера на С# и клиента на Java.


Вот простейший вариант с использованием пула тредов.

Код:
using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        public const int port = 8081;

        public static void ClientServerDialog(object _client)
        {
            Console.WriteLine("client accepted");
            TcpClient client = (TcpClient) _client;
            try {            
                Stream stream = client.GetStream( );
                // do in/out operations
               
            } finally {
                client.Close( );
                Console.WriteLine("client leaved");
            }
        }

        static void Main(string[] args)
        {            
            TcpListener listener = new TcpListener(port);
            listener.Start( );
            Console.WriteLine("starting listening to port {0}", port);
            try {
                while (true) {                    
                    TcpClient client = listener.AcceptTcpClient( );
                    // fork new thread from process thread pool for new client
                    ThreadPool.QueueUserWorkItem(ClientServerDialog, client);
                }
            } finally {
                listener.Stop( );
                Console.WriteLine("listening terminated");
            }
        }
    }
}

в пуле кажется 24 рабочие нитки, т.о. именно этим числом ограничено максимальное количество обрабатываемых в единый момент времени клиентов.

учти, что System.Runtime.Serialization тебе не удасться использовать для диалога с клиентом на Java, потому тебе придётся передвать unicode-строки в собственном формате (например передавать в сеть сначала длину строки, потом поток байтов).
17K
16 декабря 2006 года
Mikeprosoft
15 / / 14.10.2006
Вот это мне очень понравилось.
А как потом идентифицировать клиентов, если допустим они отправляют запросы с разных ip или в запросах разные строки(ну т.е. логин например отсылают) ?
Просто мне нужно определенному клиенту отвечать определенным запросом.
5
16 декабря 2006 года
hardcase
4.5K / / 09.08.2005
Цитата: Mikeprosoft
А как потом идентифицировать клиентов, если допустим они отправляют запросы с разных ip или в запросах разные строки(ну т.е. логин например отсылают) ?
Просто мне нужно определенному клиенту отвечать определенным запросом.


Можно считать, что на каждого клиента создаётся отдельный поток в лице метода ClientServerDialog. В контексте потока тебе доступен объект client типа TcpClient.
Вот пример дальнейшего развития представленного ранее кода.

Код:
using System.Collections.Generic;
using System.ComponentModel;
<...>
public static void ClientServerDialog(object _client)
{
    using(MyClient newClient = new MyClient((TcpClient) _client) {
        newClient.Execute();
    }        
}

public class MyClient: IDisposable
{
    public static List<MyClient> Clients = new List<MyClient>( );
    public static int BufferSize = 4096;        

    private TcpClient client;
    public TcpClient Client { get { return client; } }

    public MyClient(TcpClient client)
    {
        this.client = client;
        lock (Clients) {
            Clients.Add(this);
        }
        Console.WriteLine("client accepted");
    }

    ~MyClient( )
    {
        lock (Clients) {
            Clients.Remove(this);
        }
        Dispose(false);
        Console.WriteLine("client leaved");
    }

    public void Execute( )
    {
        Stream stream = new BufferedStream(Client.GetStream( ), BufferSize);
        // in/out operations;
    }

    // Track whether Dispose has been called.
    private bool disposed = false;

    // Implement IDisposable.
    void IDisposable.Dispose( )
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        // Check to see if Dispose has already been called.
        if (!this.disposed) {
            client.Close( );
        }
        disposed = true;
    }
}

Здесь в каждом потоке создаётся новый объект MyClient, инкапсулирующий TcpClient-клиента.
MyClient.Clients - это список всех текущих экземпляров MyClient.

в методе Execute() предполагается выполненние всех операций ввода-вывода с клиентом.

замечание:
конструкция
Цитата:

using(ObjectType obj = new ObjectType()) {
}


предполагает реализацию у ObjectType интерфейса IDisposable, потому как после } автоматически вызывается obj.Dispose(), который должен возвращать ресурсы, занятые объектом obj - в нашем случае это ресурсы, отноясщиеся к TcpClient'у, который необходимо закрыть методом Close().

17K
16 декабря 2006 года
Mikeprosoft
15 / / 14.10.2006
а я чета не понял, как тогда отправлять клиенту ответ? =) где?
5
17 декабря 2006 года
hardcase
4.5K / / 09.08.2005
а stream тебе на что?
уж и в поток писать нельзя?

в духе работы с текстовым файлом:
Код:
public void Execute( )
{
    Stream stream = new BufferedStream(Client.GetStream( ), BufferSize);
    StreamWriter writer = new StreamWriter(stream);
    StreamReader reader = new StreamReader(stream);
   
// write    
    writer.WriteLine("hi client, this is greeting from server!!!");
    writer.Flush();
   
// read
    string reply = reader.ReadLine();
}


В Java есть аналогичные классы StreamReader и StreamWriter - их будет удобно использовать на клиенте.
17K
17 декабря 2006 года
Mikeprosoft
15 / / 14.10.2006
Ну да, я так и думал. Спасибо. А теперь насчет клиента.
Есть функция:
 
Код:
public void tcp()   //отправка сообщений серваку
        {          
           TcpClient Tc = new TcpClient(ip, 80);
           StreamWriter sw = new StreamWriter(Tc.GetStream());
           StreamReader sr = new StreamReader(Tc.GetStream());
           sw.WriteLine(w);
           sw.Flush();
           r = sr.ReadLine();    
        }

И в нужном месте она вызывается(т.е. отправляет серверу ответ и получает). А как сделать, чтобы клиент находился в ожидании(при этом и клиент и сервер - WinApplication) получения сообщений от сервера. И как только он получает определенный ответ, так выполняет что-то.
713
17 декабря 2006 года
Ap0k
360 / / 13.03.2006
Mikeprosoft, учи мат. часть. Тебе дали несколько ответов которые помогли бы тебе в создании сервера, но создавать его целиком, отвечая на все тривиальные вопросы никто наверно не захочет...
PS: метод Read класса Stream будет ждать данных от клиента.
17K
24 декабря 2006 года
Mikeprosoft
15 / / 14.10.2006
OK. Насчет клиента - создам новую ветку. А теперь вернемся к нашим баранам.
Код:
public void Execute()
   {
    try
       {
         int go = 0;
        Stream streamm = new BufferedStream(Client.GetStream(), BufferSize);
        srrr = new StreamReader(streamm);
        swww = new StreamWriter(streamm);
        string ssrx = srrr.ReadLine();  // на этой строке почему-то зависает
        string XXX, YYY;
        double found = 0;
        int reg = 0;


На той строке, что я обозначил, почему-то не происходит считывание данных.
5
24 декабря 2006 года
hardcase
4.5K / / 09.08.2005
Цитата: Mikeprosoft
 
Код:
string ssrx = srrr.ReadLine();  // на этой строке почему-то зависает
На той строке, что я обозначил, почему-то не происходит считывание данных.


Так зависает или НЕ считывает?
А ты пробовал записывать С другой стороны потока?

Если певый случай, то ReadLine() производит блокирующий вызов и ждёт данных из потока.

Можешь в принципе убрать слой BufferedStream и читателя/писателя создавать сразу из NetworkStream'а

17K
24 декабря 2006 года
Mikeprosoft
15 / / 14.10.2006
с глюком разобрался, ждите новых вопросов =)
18K
10 января 2007 года
QuaNtuM
3 / / 10.06.2006
Я делал так: передавал информацию в виде строк, каждая строка - это XML - документ. При подключении каждый клиент у меня регистрировался, присылая опознавательный XML-документ. Ну и работа с клиентам были с помощью документиков с двумя узлами - type и data. Где data в свою очередь тоже мог быть XML - документом. И в зависимости от содержания узла data велась определенная работа с клиентом, т.е. содержимое узла data передавалось в соответствующий метод.
17K
25 января 2007 года
Виктор А.
36 / / 10.01.2007
Во всех фнукциях чтения из сокета (не важно, читаем с потока или как) - обязательно заключать строку (как минимум) count_read = ...read(...) в защищенный код (try{}cath{}) - иначе, в случае отсутсвия синхронизации м/ж клиентом и сервером, может выскочить исключение (типа "я читаю, а он-то уже разъединился...").
PS: конечно, это не константное утверждение, но как предостережение...
PPS: И, в потоке лучше работать с блокирующим сокетом, при этом, что бы не замораживать поток ожиданием очередной порции данных - надо установить приемлимое время на чтение (см. доступные методы используемого тобой транспортного класса). К стати, то, что не происходит чтение из srrrr.ReadLine()... - подтверждение выше сказанного. Просто на той стороне клиент не отправил данные, или ещё что - не важно, метод ждёт данных... Ставь время... можно например, 1000 - может вполне хватить.
30K
25 августа 2007 года
gerich_home
8 / / 25.08.2007
Здравствуй Alektrik, заходи на форум VisualBasic -> Присоединяйтесь к совместному написанию программы!
Мне хочется организовать группу программистов. Нужна любая поддержка и идеи.
Язык программирования, на котором ты пишешь значения не имеет!
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог