Программирование сокетов с C # - PullRequest
2 голосов
/ 12 января 2009

Я создаю клиент-серверное приложение для периодического резервного копирования определенных файлов. По сути, клиент будет отслеживать определенные файлы на предмет изменений и загружать их на сервер. Затем сервер получит их и сохранит с возрастающим постфиксом (т. Е. "filename_v1", "filename_v2" и т. Д.). Теперь мне удалось выполнить большую часть этого, но возникли некоторые проблемы, и я не смог найти ничего, связанного с ними.

Прежде чем начать, обратите внимание:

  • Я приложил все усилия, чтобы найти решение самостоятельно.
  • Я следовал (и закончил) нескольким учебникам по программированию сокетов.
  • Я не знаю никого с опытом программирования на c # и / или сокетах.

Вот логика:

  1. Сервер запускается, начинает слушать. (BeginAccept)
  2. Когда клиент подключается, создается «рабочий» сокет.
  3. Рабочий сокет начинает получать. (BeginReceive) / Клиент отправляет файл (SendFile)
  4. Когда данные получены, файл сохраняется. (также проверяет более ранние версии, но здесь это не имеет значения.)
  5. перейти к 3. (нам нужно получить больше файлов от одного и того же клиента.)

шаги 1-4 работают просто отлично.

Вот проблема: на шаге 5, хотя сервер ничего не получает, вызывается onDataReceive (метод обратного вызова), и сервер попадает в бесконечный цикл. Я пытался закрыть (или отключить) рабочий сокет, но шансов там нет. Я начинаю подозревать, что, возможно, мой алгоритм немного небрежный.

В любом случае, любые комментарии, предложения или помощь приветствуются.

Ответы [ 3 ]

2 голосов
/ 12 января 2009

Ваш обратный вызов реализует EndReceive?

Вы передаете объект состояния? Если это так, пусть одно из свойств будет буфером, который вы передаете в BeginReceive, затем в вашем обратном вызове проверьте буфер состояния, чтобы увидеть, были ли получены какие-либо данные. Если нет, не продолжайте цикл.

struct SocketStateObject
{
  public byte[] Buffer;
  public Socket Socket;
}



Socket mySocket = new Socket(...);
SocketStateObject state;
state.Buffer = new byte[1024];
state.Socket = mySocket;

socket.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, callback, state);

//don't remember the signature
public void callback(IAsyncResult a)
{
  if (((SocketStateObject)a.State).Buffer.Length = 0)
    //don't call socket.beginreceive again.
}
1 голос
/ 12 января 2009

Я думаю, тебе стоит взглянуть на WCF. Зачем изобретать колесо с программированием сокетов, если вы можете использовать приложение для обмена сообщениями, которое может легко передавать байтовый массив по проводам?

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

Предлагаю следующие ресурсы:

1 голос
/ 12 января 2009

Я провел некоторую работу над библиотекой сокетов, которая используется для передачи медицинских изображений в .NET за последний год или около того. Вначале нам было трудно определить, когда сокет отключился, но, наконец, мы нашли стабильное решение.

Наше приложение использует NetworkStream для чтения / записи в сокет. У нас есть похожая на вас цепочка, которая создается при поступлении нового соединения и используется для чтения и записи данных в сеть. Мы вызываем метод ниже для опроса, когда данные поступили или когда соединение было закрыто. Метод может быть настроен на использование более длительного тайм-аута, если вы не хотите опрашивать. Когда мы знаем, что данные доступны, мы читаем из объекта NetworkStream.

Ключевым моментом ниже является нулевой байт Send на сокете, который, кажется, обнаруживает, когда сокет выключился, как упомянуто в комментариях. Метод OnNetworkError просто вызывается, чтобы запустить отключаемый поток.

Стив


protected override bool NetworkHasData() 
{
    if (_socket == null)
        return false;

    // Tells the state of the connection as of the last activity on the socket
    if (!_socket.Connected)
    {
        OnNetworkError(null, true);
        return false;
    }

    // This is the recommended way to determine if a socket is still active, make a
    // zero byte send call, and see if an exception is thrown.  See the Socket.Connected
    // MSDN documentation.  Only do the check when we know there's no data available
    try
    {
        List readSockets = new List();
        readSockets.Add(_socket);
        Socket.Select(readSockets, null, null, 100000);
        if (readSockets.Count == 1)
        {
            if (_socket.Available > 0)
                return true;
            OnNetworkError(null, true);
            return false;
        }

        _socket.Send(new byte[1], 0, 0);
    }
    catch (SocketException e)
    {
        // 10035 == WSAEWOULDBLOCK
        if (!e.NativeErrorCode.Equals(10035))
            OnNetworkError(e, true);
    }

    return false;
}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...