Socket
От: Unforgiver Россия  
Дата: 07.10.04 12:21
Оценка:
Господа, убедительная просьба — не могли бы вы поделиться кусочком кода, связанным с применением Сокетов в C# или в VB.NET.
Бьёмся — ничего не получается.
Задача-минимум — отправить некий текст и затем получить его.

Создаем два сокета, потом пишем

socket1.Listen(1)
socket2.Connect(L) (L — адрес, определенный заранее).

Оба сокета созданы на локальной машине, порты у обоих одинаковые.

После этого выводим состояние сокетов — первый Connected = False, второй — Connected = True (т.е. тот, который был в ожидании, он так и не перешел в состояние соединения).
При этом Если не переводить первый в ожидание, второй тоже не соединяется.
Всё заканчивается плохо. Если что-то закончилось хорошо — значит оно еще не закончилось.
Re: Socket
От: Andrbig  
Дата: 07.10.04 12:49
Оценка:
Здравствуйте, Unforgiver, Вы писали:

U>Господа, убедительная просьба — не могли бы вы поделиться кусочком кода, связанным с применением Сокетов в C# или в VB.NET.


Поиск chat*.* в директории со студией делали? Там есть пара готовых примеров с сокетами.
Re[2]: Socket
От: Unforgiver Россия  
Дата: 07.10.04 13:41
Оценка:
Здравствуйте, Andrbig, Вы писали:

A>Здравствуйте, Unforgiver, Вы писали:


U>>Господа, убедительная просьба — не могли бы вы поделиться кусочком кода, связанным с применением Сокетов в C# или в VB.NET.


A>Поиск chat*.* в директории со студией делали? Там есть пара готовых примеров с сокетами.


Там не с сокетами, а как-то по другому сделано.

Мы прошли дальше
Разделили сокеты на разные компы — теперь один слушает, второй соединяется.
И вот тут беда — слушающего мы не можем перевести в состояние "соединенный" ...
КАК ЭТО СДЕЛАТЬ ?

Грубо говоря, сокет в состоянии ожидания

If ???? then socket.перевести в состояние соединения
А вот что вместо ???? поставить ?
Всё заканчивается плохо. Если что-то закончилось хорошо — значит оно еще не закончилось.
Re: Socket
От: ie Россия http://ziez.blogspot.com/
Дата: 07.10.04 16:34
Оценка:
Здравствуйте, Unforgiver, Вы писали:

U>Господа, убедительная просьба — не могли бы вы поделиться кусочком кода, связанным с применением Сокетов в C# или в VB.NET.

U>Бьёмся — ничего не получается.
U>Задача-минимум — отправить некий текст и затем получить его.

U>Создаем два сокета, потом пишем


U>socket1.Listen(1)

U>socket2.Connect(L) (L — адрес, определенный заранее).

U>Оба сокета созданы на локальной машине, порты у обоих одинаковые.


U>После этого выводим состояние сокетов — первый Connected = False, второй — Connected = True (т.е. тот, который был в ожидании, он так и не перешел в состояние соединения).

U>При этом Если не переводить первый в ожидание, второй тоже не соединяется.

Вот, недавно писал в универе таску по криптографии с использованием Socket'ов, выложу, может пригодиться. Там все достаточно просто.

User.cs
using System;
using System.Net;
using System.Net.Sockets;

namespace Iae.Nsu.Crypto.ElGamal
{
    /// <summary>
    /// Класс пользователя шифром Эль-Гамаля.
    /// </summary>
    public class User
    {
        public User(int prime)
        {
            this.p_ = prime;

            System.Random rand = new Random();
            int n, x, y;
            int t = this.p_-1;

            do
            {
                // c_ выбираем случайным образом
                this.c_ = (int)System.Math.Abs(rand.Next(t));
                // проверяем что бы НОД(c_, (p_-1)*(q_-1)) = 1
                CryptoLibrary.Math.EuclidAlgoritm(this.c_, t, out n, out x, out y);
                // если не равняется выбираем новое c_
            }    while(n != 1 || this.c_ < 2);

            this.g_ = CryptoLibrary.Math.FindGenerativeElement(this.p_);
            this.d_ = CryptoLibrary.Math.PowerByModule(this.g_, this.c_, this.p_);
        }

        private Socket sock;

        private int p_;
        private int c_;
        private int d_;
        private int g_;
        
        protected string name_;
        /// <summary>
        /// Имя пользователя.
        /// </summary>
        public string Name
        {
            get
            {
                return this.name_;
            }
            set
            {
                this.name_ = value;
            }
        }

        /// <summary>
        /// Шифруем сообщение <b>message</b> в поток байт используя 
        /// открытый ключ опонента <b>d</b>.
        /// </summary>
        /// <param name="message">Сообщение для пересылки.</param>
        /// <param name="d">Несекретная информация опонента.</param>
        /// <returns>Зашифрованное сообщение.</returns>
        public byte [] EncodeMessage(string message, int d)
        {
            int     len = message.Length;
            char [] chs = message.ToCharArray();
            int  [] its = new int[len+1];
            byte [] bts = new byte[(len+1)*4];
            int     r__;
            
            Random rand = new Random();
            int k = rand.Next(2, this.p_-1);

            r__ = CryptoLibrary.Math.PowerByModule(this.g_, k, this.p_);
            its[0] = r__;
            
            for (int i = 0; i < len; i++)
            {
                its[i+1] = CryptoLibrary.Math.PowerByModule(d, k, this.p_);
                its[i+1] = CryptoLibrary.Math.PowerByModule(its[i+1]*chs[i], 1, this.p_);
            }

            for (int i = 0; i <= len; i++)
            {
                bts[i*4+0] = (byte)(its[i]%256); its[i] /= 256;
                bts[i*4+1] = (byte)(its[i]%256); its[i] /= 256;
                bts[i*4+2] = (byte)(its[i]%256); its[i] /= 256;
                bts[i*4+3] = (byte)(its[i]%256); its[i] /= 256;
            }

            return bts;
        }

        /// <summary>
        /// Дешифровываем сообщение из потока байт <b>bytes</b> из 
        /// которых полезных <b>length</b> байт.
        /// </summary>
        /// <param name="bytes">Зафирванное сообщение.</param>
        /// <param name="length">Кол-во полезных байт.</param>
        /// <returns>Дешифрованное сообщение.</returns>
        public string DecodeMessage(byte [] bytes, int length)
        {
            int     len = length / 4;
            char [] chs = new char[len];
            int  [] its = new int[len];
            int     r__ = 0;

            for (int i = 0; i < len; i++)
            {
                its[i] += bytes[i*4+3]; its[i] *= 256;
                its[i] += bytes[i*4+2]; its[i] *= 256;
                its[i] += bytes[i*4+1]; its[i] *= 256;
                its[i] += bytes[i*4+0];
                
                if (i == 0)
                {
                    r__ = its[0];
                }
                else
                {
                    int t = CryptoLibrary.Math.PowerByModule(r__, this.p_-1-this.c_, this.p_);
                    chs[i-1] = (char)CryptoLibrary.Math.PowerByModule(t*its[i], 1, this.p_);
                }
            }

            return new string(chs);
        }

        /// <summary>
        /// Принимаем сообщение. Открываем сокет на порт <b>port</b>. 
        /// Ждем установления соединения. Затем высылаем свой открытый ключ.
        /// Ожидаем сообщение. Дешифруем его.
        /// </summary>
        /// <param name="port">Порт.</param>
        public void WaitMessage(int port)
        {
            byte [] bts = new byte[1024];
            int t = this.d_;
            int len;

            IPAddress ipAddress = new IPAddress(0);
            sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            sock.Bind(new IPEndPoint(ipAddress, port));
            sock.Listen(5);

            System.Console.WriteLine("{0}: Ожидаем запрос на установку соединения.", this.name_);
            Socket s = sock.Accept();
            System.Console.WriteLine("{0}: Соединение установленно.", this.name_);

            System.Console.WriteLine("{0}: Отправляем несекретные данные.", this.name_);
            for (int i = 0; i < 4; i++)
            {
                bts[i] = (byte)(t%256); t/=256;
            }
      s.Send(bts, 4, SocketFlags.None);

            System.Console.WriteLine("{0}: Ожидаем сообщение.", this.name_);
            len = s.Receive(bts);
            System.Console.WriteLine("{0}: Сообщение успешно принято.", this.name_);

            System.Console.WriteLine("{0}: Сообщение дешифруется.", this.name_);
            string message = this.DecodeMessage(bts, len);

            System.Console.WriteLine("{0}: Полученно сообщение:: {1}", this.name_, message);
        }

        /// <summary>
        /// Отправляем сообщение <b>message</b> на <b>IPaddress:port</b>. 
        /// Устанавливаем соединение. Получаем публичный ключ. Шифруем.
        /// Отравляем.
        /// </summary>
        /// <param name="IPaddress">Адрес опонента.</param>
        /// <param name="port">Его порт.</param>
        /// <param name="message">Сообщение для отправки.</param>
        public void SendMessage(string IPaddress, int port, string message)
        {
            IPEndPoint ipe = new IPEndPoint(IPAddress.Parse(IPaddress), port);
            Socket s = new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            byte [] bytes = new byte[4];

            s.Connect(ipe);
            if (s.Connected)
            {
                System.Console.WriteLine("{0}: Соединение установленно.", this.name_);

                System.Console.WriteLine("{0}: Ожидаем несекретные данные опонента.", this.name_);
                s.Receive(bytes);
                int dFriend = (((bytes[3]*256 + bytes[2])*256 + bytes[1])*256 + bytes[0]);

                System.Console.WriteLine("{0}: Производим шифровку и пересылку сообщения.", this.name_);

                if(s.Send(this.EncodeMessage(message, dFriend)) == (message.Length+1)*4) 
                {
                    System.Console.WriteLine("{0}: Сообщение успешно посланно.", this.name_);
                }
                else 
                {
                    System.Console.WriteLine("{0}: Ошибка при посылке сообщения.", this.name_);
                }
            }
            else
            {
                System.Console.WriteLine("{0}: Ошибка при установлении соединения.", this.name_);
            }
        }

    }
}


Main.cs
using System;
using Iae.Nsu.Crypto.CryptoLibrary;

namespace Iae.Nsu.Crypto.ElGamal
{
    /// <summary>
    /// Summary description for Class1.
    /// </summary>
    class Class1
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            User a = new User(5851);
            a.Name = "Alice";
            User b = new User(5851);
            b.Name = "Bob";

            
            System.Console.Write("Для принятия сообщения введите 1, для отправки 2: ");
            int s = System.Console.Read();
            System.Console.Read(); System.Console.Read();
            if (s == (int)'1')
            {
                System.Console.Write("Введите номер порта для принятия сообщения: ");
                int port = Int32.Parse(System.Console.ReadLine());
                a.WaitMessage(port);
            }
            else
            {
                System.Console.Write("Введите IP адрес назначения сообщения: ");
                string IPaddress = System.Console.ReadLine();
                System.Console.Write("Введите номер порта для отправки сообщения: ");
                int port = Int32.Parse(System.Console.ReadLine());
                System.Console.Write("Введите сообщение для отправки: ");
                string message = System.Console.ReadLine();

                b.SendMessage(IPaddress, port, message);
            }
            
        }
    }
}
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Превратим окружающую нас среду в воскресенье.
Re[2]: Socket
От: Unforgiver Россия  
Дата: 08.10.04 05:33
Оценка:
Здравствуйте, ie, Вы писали:


ie>Вот, недавно писал в универе таску по криптографии с использованием Socket'ов, выложу, может пригодиться. Там все достаточно просто.



Спасибо. Соединились
Просто раньше в VB 6 был контрол — WinSock, у которого было событие "Connection_Request". Типа когда на него запрос приходил, оно инициировалось.
А теперь контрола нет, и события такого соответственно тоже.

Так что — спасибо, что помог разобраться.
Удачи.
Всё заканчивается плохо. Если что-то закончилось хорошо — значит оно еще не закончилось.
Re: Socket
От: DemAS http://demas.me
Дата: 08.10.04 08:56
Оценка:
Здравствуйте, Unforgiver, Вы писали:

Реализация простейшего TCP-сервера http://www.adem.karavaevo.ru/index.php?option=content&amp;task=view&amp;id=53&amp;Itemid=2
Простейший TCP клиент http://www.adem.karavaevo.ru/index.php?option=content&amp;task=view&amp;id=63&amp;Itemid=2
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Re: Socket
От: Unforgiver Россия  
Дата: 08.10.04 12:11
Оценка:
Спасибо всем за присланные сообщения, однако возникает другая проблема:
Все описанные примеры работают с консолью (а мне надо было сразу работать с формой). Ну это не беда.
Проблема в том, что после написания

sock.Bind(...);
sock.Listen(...);

система подвисает до тех пор, пока на этот сокет не придет запрос о соединении.

Дальше идёт

Socket NewSock = sock.Accept();

и эта строка срабатывает, что логично, после того, как придет запрос (connect) от клиента.

Но вот что делать с Listen ? Как заставить приложения обрабатывать другие прерывания.
В VB 6 была функция DoEvents, но она вставлялась в цикл, чтобы во время его выполнения обрабатывать другие запросы.
Тут и функции нет (может быть она как-то по другому объявляется ?) да и цикла я не вижу.

Помогите победить.
Заранее спасибо.
Всё заканчивается плохо. Если что-то закончилось хорошо — значит оно еще не закончилось.
Re: Socket
От: Аноним  
Дата: 08.10.04 12:29
Оценка:
Как заставить приложения обрабатывать другие прерывания>
Вынесите ожидание в отдельный поток. И там вызывайте callbaсk как-нибудь.
А фунция есть — Application.ProcessEvents(), если не путаю. Но это грязный путь, говорят. Поток лучше.


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[2]: Socket
От: DemAS http://demas.me
Дата: 08.10.04 12:25
Оценка:
Здравствуйте, Unforgiver, Вы писали:

U>Но вот что делать с Listen ? Как заставить приложения обрабатывать другие прерывания.


Использовать асинхронные сокеты ?
Или как вариант .SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 3000); — но мне кажется это плохое решение.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Re[2]: Socket
От: DemAS http://demas.me
Дата: 08.10.04 12:28
Оценка:
Здравствуйте, Unforgiver, Вы писали:

Кстати, есть еще такая вещь, как Mutiplexed Sockets:

Just as in Unix, the Socket class provides the Select() method. This method is used to multiplex multiple Socket instances to watch for the ones that are ready to be read or written to. In C#, however, the Select() method is used somewhat differently. Here is the format of the Select() method:

Select(IList read, IList write, IList error,
int microseconds)
The read, write, and error parameters are IList objects, which are arrays that contain created sockets to monitor. The microseconds parameter defines the amount of time (in microseconds) the Select() method will wait for the events to happen.

The following is a small code fragment showing how the Select() method can be used:

ArrayList socketList = new ArrayList(5);
SocketList.Add(sock1);
SocketList.Add(sock2);
Socket.Select(socketList, null, null, 1000);
byte[] buffer = new byte[1024];
for (i = 0; i < socketList.Length - 1; i++)
{
  socketList[i].Receive(buffer);
  ConsoleWriteLine(Encoding.ASCII.GetString(buffer));
}


Notice that the Select() method will monitor both sock1 and sock2 for incoming data. If no data is present on either socket, the Receive() method will not block the program.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Re[2]: Socket
От: Unforgiver Россия  
Дата: 08.10.04 12:31
Оценка:
Здравствуйте, Аноним, Вы писали:

А> Вынесите ожидание в отдельный поток. И там вызывайте callbaсk как-нибудь.

А>А фунция есть — Application.ProcessEvents(), если не путаю. Но это грязный путь, говорят. Поток лучше.

Спасибо, попробую. С потоками надо еще разобраться будет. Пока не сталкивался с ними.
Всё заканчивается плохо. Если что-то закончилось хорошо — значит оно еще не закончилось.
Re[2]: Socket
От: ie Россия http://ziez.blogspot.com/
Дата: 09.10.04 13:14
Оценка:
Здравствуйте, Unforgiver, Вы писали:

U>Спасибо всем за присланные сообщения, однако возникает другая проблема:

U>Все описанные примеры работают с консолью (а мне надо было сразу работать с формой). Ну это не беда.
U>Проблема в том, что после написания

U>sock.Bind(...);

U>sock.Listen(...);

U>система подвисает до тех пор, пока на этот сокет не придет запрос о соединении.


Юзай, асинхронные сокеты:

// где-то в коде
//...
sock.Bind(...);
sock.Listen(...);
sock.BeginAccept(AsyncCallback(AcceptCallback), sock);
//...

public static void AcceptCallback(IAsyncResult ar) 
{
        Socket sock = (Socket)ar.AsyncState;
    Socket acceptSock = sock.EndAccept(ar);
        
        // тут дальше работаешь с acceptSock
}
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Превратим окружающую нас среду в воскресенье.
Re[3]: Socket
От: TechnoMen  
Дата: 19.10.05 13:22
Оценка:
Как узнать при помощи Сокетов, имеются ли ожидающие запросы на подключение?
s.Bind(ep2);
s.Listen(1);
s = s.Accept(); // На этом месте виснит программа если нет входящих запросов

В классе TcpListener есть метод Pending, как раз то что надо... Но не хотелось бы лишний класс вводить.
Re[4]: Socket
От: ie Россия http://ziez.blogspot.com/
Дата: 20.10.05 01:52
Оценка:
Здравствуйте, TechnoMen, Вы писали:

TM>Как узнать при помощи Сокетов, имеются ли ожидающие запросы на подключение?

TM>s.Bind(ep2);
TM>s.Listen(1);
TM>s = s.Accept(); // На этом месте виснит программа если нет входящих запросов

TM>В классе TcpListener есть метод Pending, как раз то что надо... Но не хотелось бы лишний класс вводить.


Для сокетов используй Poll.

if (s.Poll(waitingTimeout, SelectMode.SelectRead))
{
    sAccepted = s.Accept();
}
... << RSDN@Home 1.2.0 alpha rev. 0>>
Превратим окружающую нас среду в воскресенье.
Re[5]: Socket
От: TechnoMen  
Дата: 20.10.05 02:14
Оценка:
ie>
ie>if (s.Poll(waitingTimeout, SelectMode.SelectRead))
ie>{
ie>    sAccepted = s.Accept();
ie>}
ie>


Пробовал, почему то всегда выдает FASLE
Re[6]: Socket
От: ie Россия http://ziez.blogspot.com/
Дата: 20.10.05 03:28
Оценка:
Здравствуйте, TechnoMen, Вы писали:


TM>Пробовал, почему то всегда выдает FASLE


Показывай код, у меня все работает на ура.

Сервер:
    class Class1
    {
        private const int secondTm = 1000000; // 1 second in microseconds
        private const int timeout = 10; // seconds

        [STAThread]
        static void Main(string[] args)
        {
            using (Socket sock = new Socket(AddressFamily.InterNetwork, 
                SocketType.Stream, ProtocolType.Tcp))
            {
                sock.Bind(new IPEndPoint(Dns.Resolve("localhost").AddressList[0], 
                    8822));
                sock.Listen(10);
                // wait connection for 10 seconds 
                Console.WriteLine(sock.Poll(secondTm*timeout, SelectMode.SelectRead));
            }
        }
    }


Клиент:
    class Class1
    {
        [STAThread]
        static void Main(string[] args)
        {
            Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
                ProtocolType.Tcp);
            s.Connect(new IPEndPoint(Dns.Resolve("localhost").AddressList[0], 
                8822));
        }
    }


Если в течении 10 секунд к серверу кто-то коннектится, то на консоль попадает "True".
Превратим окружающую нас среду в воскресенье.
Re[7]: Socket
От: TechnoMen  
Дата: 20.10.05 04:22
Оценка:
ie>Если в течении 10 секунд к серверу кто-то коннектится, то на консоль попадает "True".

Разобрался.. спасибо, помог.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.