我仍在学习,并且花了很多时间尝试不同的事物并四处搜寻,但是我仍然找不到解决我问题的答案。如果有人愿意显示一些代码或告诉我怎么做,那将非常有帮助。如果没有办法,解决方法也可能会有所帮助。什么都没有。
基本上,我需要将多个客户端连接到服务器,侦听两端都接收到序列化的类,并能够将相同的类(在两端响应并随意序列化)发送给另一个。
对于客户的应用程序:我需要能够侦听特定端口上的主机(并接收序列化的类,然后连续对其进行反序列化),并且还可以随意发送一个并作为响应。
对于服务器的应用程序:我需要能够侦听同一端口上的任何传入连接(任何IP),然后将该连接隔离为另一个线程上的单个连接,并继续侦听其上的序列化类。并能够再次发送(随意,随意和回复)。
为什么要全部使用一个端口?:我的ISP不允许我打开多个端口。
以下是我目前正在使用的一些代码:
// 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()为空。
注意:“ cpuList”是字典键(作为字符串)的列表框,“ btnServer”用于启动TcpListener,“ btnClient”用于启动TcpClient,“ txtSend”是我输入要发送到的文本的位置列表框中选择的TcpClient。