singlepost

Приложение клиент-сервер на C# << На главную или назад  

Уменя есть 2 части – 2 приложения. Это простой чат. Программирую в VS 2008.
Пример взял из книжки.
Почему не работает не понимаю
Серверная часть
public class Server : System.Windows.Forms.Form
{
private System.Windows.Forms.TextBox inputTextBox;
private System.Windows.Forms.TextBox displayTextBox;
private Socket connection;
private Thread readThread;
private System.ComponentModel.Container component = null;
private NetworkStream socketStream;
private BinaryWriter writer;
private BinaryReader reader;

public Server()
{
InitializeComponent();

readThread = new Thread(new ThreadStart(RunServer));
readThread.Start();
}

[STAThread]
static void Main()
{
Application.Run(new Server());
}

protected void Server_Closing(object sender, CancelEventArgs e)
{
System.Environment.Exit(System.Environment.ExitCode);
}

protected void inputTextBox_KeyDown(object sender, KeyEventArgs e)
{
// отправка текста клиенту
try
{
if (e.KeyCode == Keys.Enter && connection != null)
{
writer.Write("SERVER» > " + inputTextBox.Text);

displayTextBox.Text += "\r\nSERVER»> " + inputTextBox.Text;

if (inputTextBox.Text == "TERMINATE") connection.Close();

inputTextBox.Clear();
}
}
catch (SocketException)
{
displayTextBox.Text += "\nError writing object";
}
}

public void RunServer()
{
TcpListener listener;
int counter = 1;

try
{
listener = new TcpListener(5000);

listener.Start();

while (true)
{
displayTextBox.Text = "Waiting for connection\r\n";

connection = listener.AcceptSocket();

socketStream = new NetworkStream(connection);

writer = new BinaryWriter(socketStream); reader = new BinaryReader(socketStream);
displayTextBox.Text += "Connection " + counter + "received.\r\n";

writer.Write("SERVER»>,Connection successful");

inputTextBox.ReadOnly = false; string theReply = "";
do
{
try
{
theReply = reader.ReadString();

displayTextBox.Text += "\r\n" + theReply;
}

catch (Exception)
{
break;
}

} while (theReply != "CLIENT»> TERMINATE" && connection.Connected);

displayTextBox.Text += "\r\nUser terminated connection";

inputTextBox.ReadOnly = true;
writer.Close();
reader.Close();
socketStream.Close();
connection.Close();

++counter;
}
}

catch (Exception error)
{
MessageBox.Show(error.ToString());
}

}

private void InitializeComponent()
{
this.SuspendLayout();

this.ClientSize = new System.Drawing.Size(292, 260);
this.Name = "Server";
this.Text = "Сервер";
this.ResumeLayout(false);

}
}

27 ответов в теме “Приложение клиент-сервер на C#”

  1. 14
    Димка Прокофьев ответил:

    Ого спасибо тебе огромное!

  2. 13
    Дмитрий Welt ответил:

    Клиентская часть:

    using System;
    using System.Windows.Forms;
    using System.Threading;
    using System.Net.Sockets;
    using System.IO;

    public partial class frmClientChatForm : Form
    {
    public frmClientChatForm()
    {
    InitializeComponent();
    }

    private NetworkStream output;
    private BinaryWriter writer;
    private BinaryReader reader;
    private Thread readThread;
    private string message = "";

    private void frmClientChatForm_Load( object sender, EventArgs e )
    {
    readThread = new Thread( new ThreadStart( RunClient ) );
    readThread.Start();
    }

    private void frmClientChatForm_FormClosing( object sender,
    FormClosingEventArgs e )
    {
    System.Environment.Exit( System.Environment.ExitCode );
    }

    private delegate void DisplayDelegate( string message );

    private void DisplayMessage( string message )
    {
    if ( displayTextBox.InvokeRequired )
    {
    Invoke( new DisplayDelegate( DisplayMessage ),
    new object[] { message } );
    }
    else
    displayTextBox.Text += message;
    }

    private delegate void DisableInputDelegate( bool value );

    private void DisableInput( bool value )
    {
    if ( inputTextBox.InvokeRequired )
    {
    Invoke( new DisableInputDelegate( DisableInput ),
    new object[] { value } );
    }
    else
    inputTextBox.ReadOnly = value;
    }

    private void inputTextBox_KeyDown( object sender, KeyEventArgs e )
    {
    try
    {
    if ( e.KeyCode == Keys.Enter && inputTextBox.ReadOnly == false )
    {
    writer.Write( "CLIENT>>> " + inputTextBox.Text );
    displayTextBox.Text += "\r\nCLIENT>>> " + inputTextBox.Text;
    inputTextBox.Clear();
    }
    }
    catch ( SocketException )
    {
    displayTextBox.Text += "\nОшибка при записи объекта";
    }
    }

    public void RunClient()
    {
    TcpClient client;

    try
    {
    DisplayMessage( "Подготовка к подключению…\r\n" );

    client = new TcpClient();
    client.Connect( "127.0.0.1", 50000 );

    output = client.GetStream();

    writer = new BinaryWriter( output );
    reader = new BinaryReader( output );

    DisableInput( false );

    do
    {
    try
    {
    message = reader.ReadString();
    DisplayMessage( "\r\n" + message );
    }
    catch ( Exception )
    {
    System.Environment.Exit( System.Environment.ExitCode );
    }
    } while ( message != "SERVER>>> TERMINATE" );

    writer.Close();
    reader.Close();
    output.Close();
    client.Close();

    Application.Exit();
    }
    catch ( Exception error )
    {
    MessageBox.Show( error.ToString(), "Ошибка Соединения",
    MessageBoxButtons.OK, MessageBoxIcon.Error );
    System.Environment.Exit( System.Environment.ExitCode );
    }
    }
    }

  3. 12
    Дмитрий Welt ответил:

    В общем вот, вся программа целиком… написал в комментариях что к чему

    Серверная часть:

    using System;
    using System.Windows.Forms;
    using System.Threading;
    using System.Net;
    using System.Net.Sockets;
    using System.IO;

    public partial class frmServerChatForm : Form
    {
    publicfrmServerChatForm()
    {
    InitializeComponent();
    }

    private Socket connection;
    private Thread readThread;
    private NetworkStream socketStream;
    private BinaryWriter writer;
    private BinaryReader reader;

    private voidfrmServerChatForm_Load( object sender, EventArgs e )
    {
    readThread = new Thread( new ThreadStart( RunServer ) );
    readThread.Start();
    }

    private voidfrmServerChatForm_FormClosing(object sender,
    FormClosingEventArgs e)
    {
    System.Environment.Exit(System.Environment.ExitCode);
    }

    // делегат, позволяющий вызывать метод DisplayMessage
    // от имени потока, отвечающего за создание GUI
    private delegate void DisplayMessageDelegate( string message );

    // метод, добавляющий клиентское сообщение в поле
    // displayTextBox.InvokeRequired возвращает True,
    // если запрос идет НЕ от имени потока-создателя
    private void DisplayMessage( string message )
    {
    if ( displayTextBox.InvokeRequired )
    {
    Invoke( new DisplayMessageDelegate( DisplayMessage ),
    new object[] { message } );
    }
    else
    displayTextBox.Text += message;
    }

    // делегат, позволяющий вызывать метод DisableInput
    // от имени потока, отвечающего за создание GUI
    private delegate void DisableInputDelegate( bool value );

    // метод, запрещающий ввод в поле
    // осуществляется по аналогии с DisplayMessage
    private void DisableInput( bool value )
    {
    if ( inputTextBox.InvokeRequired )
    {
    Invoke( new DisableInputDelegate( DisableInput ),
    new object[] { value } );
    }
    else
    inputTextBox.ReadOnly = value;
    }

    // хэндлер на нажатие клавиш
    private void inputTextBox_KeyDown( object sender, KeyEventArgs e )
    {
    try
    {
    if ( e.KeyCode == Keys.Enter && inputTextBox.ReadOnly == false )
    {
    writer.Write( "SERVER>>> " + inputTextBox.Text );
    displayTextBox.Text += "\r\nSERVER>>> " + inputTextBox.Text;

    if ( inputTextBox.Text == "TERMINATE" )
    connection.Close();

    inputTextBox.Clear();
    }
    }
    catch ( SocketException )
    {
    displayTextBox.Text += "\nОшибка при записи объекта";
    }
    }

  4. 11
    Дмитрий Welt ответил:

    Серверная часть, продолжение…

    // метод, отвечающий за создание и поддержку соединения
    public void RunServer()
    {
    TcpListener listener;
    int counter = 1;

    try
    {
    IPAddress local = IPAddress.Parse( "127.0.0.1" );
    listener = new TcpListener( local, 50000 );

    listener.Start();

    while ( true )
    {
    DisplayMessage( "Ожидание соединения…\r\n" );

    connection = listener.AcceptSocket();

    socketStream = new NetworkStream( connection );

    writer = new BinaryWriter( socketStream );
    reader = new BinaryReader( socketStream );

    DisplayMessage( "Connection " + counter + " received.\r\n" );

    writer.Write( "SERVER>>> Соединение успешно" );

    DisableInput( false );

    string theReply = "";

    do
    {
    try
    {
    theReply = reader.ReadString();

    DisplayMessage( "\r\n" + theReply );
    }
    catch ( Exception )
    {
    break;
    }
    } while ( theReply != "CLIENT>>> TERMINATE"&&
    connection.Connected );

    DisplayMessage( "\r\nПользователь отключил соединение\r\n" );

    writer.Close();
    reader.Close();
    socketStream.Close();
    connection.Close();

    DisableInput( true );
    counter++;
    }
    }
    catch ( Exception error )
    {
    MessageBox.Show( error.ToString() );
    }
    }
    }

  5. 10
    Димка Прокофьев ответил:

    Нет проси до конца не понимаю. :( Напиши пожалуйста парочку для этого кода.

  6. 9
    Дмитрий Welt ответил:

    Нда, что это за автор учебника такой, у которого код в примерах не работает? :)
    Ну тут скорее всего дело в том, что вы выделяете отдельный поток для выполнения различных задач приложения:

    readThread = new Thread(new ThreadStart(RunServer));
    readThread.Start();

    readThread = new Thread(new ThreadStart(RunClient));
    readThread.Start();

    но, поскольку не рекомендуется делать манипуляции с элементами от имени любого потока, кроме того, что был использован для их создания, то он и выдает ошибку…

    Ну а решение этой проблемы – создание нескольких делегатов, которые будут выполнять операцию от имени потока-создателя. Надеюсь понятно объяснил? :)

  7. 8
    Павел Потапов ответил:

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

  8. 7
    Димка Прокофьев ответил:

    После компиляции выдаёт окно а там
    System.InvalidOperation: Недопустимая операция в нескольких потоках: попытка доступа к элнменту управления "displayTextBox" не из того потока, в котором он был создан.
    в System.Windows.Forms.Control.get_Handle()
    в System.Windows.Forms.Control.set_WindowText(String value)
    в System.Windows.Forms.TextBoxBase.set_WindowText(String value)
    в System.Windows.Forms.Control.set_Text(String value)
    в System.Windows.Forms.TextBoxBase.set_Text(String value)
    в System.Windows.Forms.TextBox.set_Text(String value)
    в System.RunServer() в Server.cs

  9. 6
    Дмитрий Welt ответил:

    Насчет первого, сделайте как я уже описал выше.

    Ну а предупреждения со 2 по 4 объясняют почему не отображаются элементы. Короче, просто удалите строки их объявления, перетащите нужные из тулбокса на форму и дайте им такие же имена.

  10. 5
    Димка Прокофьев ответил:

    Предупреждение 1 "System.Net.Sockets.TcpListener.TcpListener(int)" является устаревшим: "This method has been deprecated. Please use TcpListener(IPAddress localaddr, int port) instead. //go.microsoft.com/fwlink/?linkid=14202&quot; Server.cs 80 24

    Предупреждение 2 Полю "Server.inputTextBox" нигде не присваивается значение, поэтому оно всегда будет иметь значение по умолчанию null Server.cs 13 42

    Предупреждение 3 Полю "Server.displayTextBox" нигде не присваивается значение, поэтому оно всегда будет иметь значение по умолчанию null Server.cs 14 42

    Предупреждение 4 Полю "Server.component" присвоено значение, но оно ни разу не использовано Server.cs 18 45

    а ещё не отображаются элементы

  11. 4
    Дмитрий Welt ответил:

    если при компиляции ошибок не выдает, то могу предположить, что вот этот код:

    listener = new TcpListener(5000);
    listener.Start();

    стоит заменить на

    System.Net.IPAddress local = System.Net.IPAddress.Parse("127.0.0.1");
    listener = new System.Net.Sockets.TcpListener(local, 5000);

    либо порт 5000 уже занят другим приложением, попробуйте изменить на другое значение

  12. 3
    Евгений Козобродов ответил:

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

  13. 2
    Леонид Максимов ответил:

    а что говорит? тут не все телепаты.

  14. 1
    Димка Прокофьев ответил:

    Клиентская часть

    public class Client : System.Windows.Forms.Form
    {
    private System.Windows.Forms.TextBox inputTextBox;
    private System.Windows.Forms.TextBox displayTextBox;

    private NetworkStream output;
    private BinaryWriter writer;
    private BinaryReader reader;

    private string message = "";

    private Thread readThread;

    private System.ComponentModel.Container components = null;

    public Client()
    {
    InitializeComponent();
    readThread = new Thread(new ThreadStart(RunClient));
    readThread.Start();
    }

    [STAThread]
    static void Main()
    {
    Application.Run(new Client());
    }

    protected void Client_Closing(object sender, CancelEventArgs e)
    {
    System.Environment.Exit(System.Environment.ExitCode);
    }

    protected void inputTextBox_KeyDown(object sender, KeyEventArgs e)
    {
    try
    {
    if (e.KeyCode == Keys.Enter)
    {
    writer.Write("CLIENT»> " + inputTextBox.Text);

    displayTextBox.Text += "\r\nCLIENT»> " + inputTextBox.Text;

    inputTextBox.Clear();
    }
    }
    catch (SocketException ioe)
    {
    displayTextBox.Text += "\nError writing object";
    }
    }

    public void RunClient()
    {
    TcpClient client;

    try
    {
    displayTextBox.Text += "Attempting' connection\r\n";

    client = new TcpClient();
    client.Connect("localhost", 5000);

    output = client.GetStream();

    writer = new BinaryWriter(output);
    reader = new BinaryReader(output);

    displayTextBox.Text += "\r\nGot I/O streams\r\n";

    inputTextBox.ReadOnly = false;

    do
    {

    try
    {
    message = reader.ReadString();
    displayTextBox.Text += "\r\n" + message;
    }

    catch (Exception)
    {
    System.Environment.Exit(System.Environment.ExitCode);
    }
    } while (message != "SERVER>>> TERMINATE");

    displayTextBox.Text += "\r\nClosing connetion.\r\n";

    writer.Close();
    reader.Close();
    output.Close();
    client.Close();
    Application.Exit();
    }

    catch (Exception error)
    {
    MessageBox.Show(error.ToString());
    }
    }

    private void InitializeComponent()
    {
    this.SuspendLayout();
    //
    // Client
    //
    this.ClientSize = new System.Drawing.Size(292, 260);
    this.Name = "Client";
    this.Text = "Клиент";
    this.ResumeLayout(false);
    }
    }

Клуб программистов работает уже ой-ой-ой сколько, а если поточнее, то с 2007 года.