Я все еще учусь и потратил приличное количество времени, пробуя разные вещи и ища, но я все еще не могу найти ответ на свою проблему.Если кто-то захочет показать какой-нибудь код или сказать мне как, это будет чрезвычайно полезно.Если нет способа, обходные пути также могут быть полезны.Все что угодно.
По сути, мне нужно подключить несколько клиентов к серверу, прослушивать получение сериализованного класса на обоих концах и иметь возможность отправлять один и тот же класс (сериализованный, в ответ и набудет (с обоих концов) к другому.
Для клиентского приложения: мне нужно иметь возможность прослушивать хост на определенном порту (и получать сериализованный класс, затем непрерывно десериализовать его),а также отправлять одно как по желанию, так и в ответ.
Для серверного приложения: мне нужно иметь возможность прослушивать любые входящие соединения (любой IP) на этом же порту, а затем изолировать соединение какодиночное соединение в другом потоке, прослушивание сериализованного класса в нем (непрерывно), а также возможность отправки одного (снова, по желанию и в ответ).
Почему один порт для всего этого ?: МойИнтернет-провайдер не позволит мне открыть более 1 порта.
Вот мой текущий работающий код:
// the serializable class (currently)
[ System.Serializable ] public class Packet {
public System.String str { get; set; }
public System.Drawing.Image img { get; set; }
}
// to deserialize the class
Packet pkt = ( Packet ) ( new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter() ).Deserialize( network_stream );
// to serialize and send the class
( new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter() ).Serialize( network_stream, pkt );
(я знаю, что это не так много, но сейчас яве мнерасскажите обо всем остальном до такой степени, что, вероятно, бесполезно публиковать то, что я в последний раз пробовал для клиента / сервера.Кроме того, если мне нужно будет предоставить что-то еще, дайте мне знать, я новичок во всем этом, заранее извиняюсь.)
РЕДАКТИРОВАТЬ: я сделал другой проект, немного более чистый, безНикакой сериализации пока нет, и это все еще не работает.Что я здесь не так делаю?(Я просматривал это несколько раз, и я знаю, что что-то упустил, я просто не знаю, где и что.)
Вот полный источник:
namespace TCP {
public partial class Main_Form : System.Windows.Forms.Form {
private System.Net.IPAddress Sea = System.Net.IPAddress.Any; // Listening address
private System.Net.IPAddress Crew = System.Net.IPAddress.Parse( "127.0.0.1" ); // Host address
private System.UInt16 Port = 888;
private Ship Ship = null; // TcpListener
private Crewmate Pirate = null; // TcpClient
public Main_Form() {
this.InitializeComponent();
}
private void btnServer_Click( System.Object sender, System.EventArgs e ) {
if( this.Ship == null ) { // only create 1 instance for testing purposes
this.Ship = new Ship { addr = this.Sea, port = this.Port, form = this }; // Connect TcpListener to 0.0.0.0:888 (Listening address & Port), and bind (form = this) for external use
}
}
private void btnClient_Click( System.Object sender, System.EventArgs e ) {
if( this.Pirate == null ) { // only create 1 instance for testing purposes
this.Pirate = new Crewmate { addr = this.Crew, port = this.Port }; // Connect TcpClient to 127.0.0.1:888 (Host address & Port)
}
}
private void txtSend_KeyDown( System.Object sender, System.Windows.Forms.KeyEventArgs e ) {
if( e.KeyCode == System.Windows.Forms.Keys.Enter ) {
e.Handled = true;
var TextMessage = this.txtSend.Text;
this.txtSend.Clear();
this.Ship.Post( TextMessage );
}
}
public System.String GetCurrentCrewmate() { // for external use
if( this.cpuList.SelectedItems.Count != 1 ) {
return( System.String.Empty );
}
return( this.cpuList.SelectedItems[ 0 ].ToString() );
}
public void EnlistCrewmate( System.String key ) { // also for external use
this.cpuList.Items.Add( key );
this.cpuList.SelectedIndex = this.cpuList.Items.Count - 1;
}
}
public static class Thread {
public static void Start( System.Action func ) {
System.Threading.ThreadPool.QueueUserWorkItem( new System.Threading.WaitCallback( delegate( System.Object state ) { func(); } ) );
}
}
public static class Debug {
public static void Write( System.String line ) {
System.Console.WriteLine( line );
}
public static void WriteBlock( System.String prefix, System.String suffix, System.String block ) {
Debug.Write( prefix );
Debug.Write( block );
Debug.Write( suffix );
}
}
public class Crewmate {
public System.String serial;
public System.Net.IPAddress addr;
public System.UInt16 port;
private System.Net.Sockets.TcpClient Pirate;
public Crewmate() {
this.Pirate = new System.Net.Sockets.TcpClient(); // create TcpClient on init
Debug.Write( "[Crewmate] Pirate connecting to Ship..." );
Thread.Start( this.Listen ); // start listening
}
private void Listen() {
while( true ) { // loop to stay connected as much as possible
while( !this.Pirate.Client.Connected ) { // while not connected, try to connect to host
try {
this.Pirate.Client.Connect( addr, port );
Debug.Write( "[Crewmate] Pirate connected to Ship!" );
}
catch {
Debug.Write( "[Crewmate] Pirate is having some connection issues..." );
}
}
while( this.Pirate.Client.Connected ) { // while connected to host, try to read data
var NetworkStream = this.Pirate.GetStream();
var Reader = new System.IO.StreamReader( NetworkStream );
while( true ) { // loop reading data (on Can Read & Data Abailable)
if( NetworkStream.CanRead && NetworkStream.DataAvailable ) {
Debug.Write( "[Crewmate] Data is available to read, proceeding..." );
try {
Debug.Write( "[Crewmate] Ship->Crew: \"" + Reader.ReadToEnd() + "\"" );
}
catch( System.Exception ex ) {
Debug.Write( "[Crewmate] Couldn't read data for some reason... Hmm..." );
Debug.Write( "[Message]" + ex.Message + "[/Message]" );
Debug.WriteBlock( "[StackTrace]", "[/StackTrace]", ex.StackTrace );
}
}
}
}
Debug.Write( "[Crewmate] Pirate lost connection to Ship." ); // when connection lost to host
}
}
public void Post( System.String String ) {
Debug.Write( "[Crewmate] Attempting to send message to Ship..." );
// Send to Ship {
var Writer = new System.IO.StreamWriter( this.Pirate.GetStream() );
Writer.Write( String );
Writer.Flush();
// }
Debug.Write( "[Crewmate] Message sent to Ship!" );
}
}
public class Ship {
public System.String serial;
public System.Net.IPAddress addr;
public System.UInt16 port;
private System.Collections.Generic.Dictionary< System.String, System.Net.Sockets.TcpClient > Crew =
new System.Collections.Generic.Dictionary< System.String, System.Net.Sockets.TcpClient >();
public Main_Form form;
public Ship() {
Debug.Write( "[Ship] Ship starting..." );
Thread.Start( this.Listen ); // start listening
}
private void Listen() {
while( true ) { // loop to stay connected as much as possible
try {
var Listener = new System.Net.Sockets.TcpListener( addr, port ); // try to create TcpListener
Listener.Start(); // try to start listening
Debug.Write( "[Ship] Ship is now running!" );
while( true ) { // loop while listening
var Pirate = Listener.AcceptTcpClient(); // accept TcpClient
Debug.Write( "[Ship] Pirate accepted to Crew." );
Thread.Start( delegate { this.HandleCrewmate( Pirate ); } ); // thread TcpClient via HandleCrewmate for further individual handling
Debug.Write( "[Ship] Pirate being sent onboard..." );
}
}
catch {
Debug.Write( "[Ship] Ship is currently refusing to listen on " + this.addr.ToString() + ":" + this.port ); // when TcpListener refuses to bind to addr:port
}
}
}
public System.Net.Sockets.TcpClient GetCrewmate( System.String key ) { // get TcpClient from Dictionary by key
System.Net.Sockets.TcpClient result;
var exists = this.Crew.TryGetValue( key, out result );
if( exists ) {
return( result );
}
return( null );
}
public System.Boolean IsCrewmateListed( System.String key ) { // test if TcpClient exixts by key
return( this.GetCrewmate( key ) != null );
}
private void PutCrewmate( System.String key, System.Net.Sockets.TcpClient value ) { // for later use, to update existing clients if they've only lost connection, this is where class (de/)serialization will come into play
if( this.IsCrewmateListed( key ) ) {
this.Crew[ key ] = value;
}
else {
this.Crew.Add( key, value );
}
}
private void LostCrewmate( System.String key ) { // when we lost connection to a TcpClient, remove them from the list (this will also be handled later on)
if( this.IsCrewmateListed( key ) ) {
this.Crew.Remove( key );
}
}
private void HandleCrewmate( System.Net.Sockets.TcpClient Pirate ) { // for handling TcpClients individually
Thread.Start( delegate {
// Enlist Pirate for the Ship to see (add TcpClient to ListBox with Dictionary Key as a name)... {
var key = "Pirate #1";
this.PutCrewmate( key, Pirate );
this.EnlistCrewmate( key );
// }
var NetworkStream = Pirate.GetStream();
var Reader = new System.IO.StreamReader( NetworkStream );
while( Pirate.Connected ) { // while connected to client
if( NetworkStream.CanRead && NetworkStream.DataAvailable ) { // try to read data (on Can Read & Data Abailable)
Debug.Write( "[Ship] Data is available to read, proceeding..." );
try {
Debug.Write( "[Ship] Crew->Ship: \"" + Reader.ReadToEnd() + "\"" );
}
catch( System.Exception ex ) {
Debug.Write( "[Ship] Couldn't read data for some reason... Hmm..." );
Debug.Write( "[Message]" + ex.Message + "[/Message]" );
Debug.WriteBlock( "[StackTrace]", "[/StackTrace]", ex.StackTrace );
}
}
}
Debug.Write( "[Ship] Lost connection to Pirate..." ); // when connection lost to client (this is also where I will handle the LostCrewmate action eventually)
} );
}
public void Post( System.String String ) {
var bytes = System.Text.Encoding.ASCII.GetBytes( String );
Debug.Write( "[Ship] Attempting to send message to selected Pirate..." );
// Send to selected Pirate only (send data to TcpClient by selected Dictionary key in ListBox)... {
var key = this.form.GetCurrentCrewmate();
if( key == System.String.Empty ) return;
var Pirate = this.GetCrewmate( key );
if( !Pirate.Connected ) return;
Debug.Write( "[Ship] Sending message to Pirate..." );
var Writer = new System.IO.StreamWriter( Pirate.GetStream() );
Writer.Write( String );
Writer.Flush();
// }
Debug.Write( "[Ship] Message sent to Pirate!" );
}
// because invoking is required, otherwise it picks up as an unsafe thread call...
private delegate void EnlistCrewmateEventHandler( System.String key );
private void EnlistCrewmate( System.String key ) {
this.form.Invoke( new EnlistCrewmateEventHandler( this.form.EnlistCrewmate ), key );
}
}
}
Что-то не так с процессом чтения, остальное похоже на проверку.Он запускается сразу после «CanRead && DataAvaialable», затем он не отображает содержимое и даже не записывает в консоль, если я что-то добавлю после этой точки, но ни одно исключение не перехватывается, очевидно, потому что он не будет отображать вывод «catch».
Проблема в основных программах: он говорит, что TcpClient.GetStream () имеет значение null.
Примечание: "cpuList" - это ListBox для словарных ключей (в виде строки), "btnServer«должен запустить TcpListener,« btnClient »- запустить TcpClient, а« txtSend »- это то, где я вводю текст для отправки выбранному TcpClient в ListBox.