基于TCP的网络游戏黑白棋系列(二):数据传输

上一节给大家演示了建立连接的关键代码,连接建立好后,就可以进行数据传输了。数据传输包含从服务器端到客户端和从客户端到服务器端,两者差别不大。

数据的传输,TcpClient的GetNetworkStream是关键,通过它我们可以得到NetworkStream网络流,客户端和服务器主要的工作就是对其读出和写入。关于如何构造稳定且性能好的网络应用,如何进行复杂的封包和解包,这里我们不考虑,我们使用StreamReader和StreamWriter来封装NetStream,读取和写入的代码如下

 1  TcpClient client;
 2  StreamReader sr;
 3  StreamWriter sw;
 4  this .userName  =   "" ;
 5  NetworkStream netStream  =  client.GetStream();
 6  sr  =   new  StreamReader(netStream, System.Text.Encoding.UTF8);
 7  sw  =   new  StreamWriter(netStream, System.Text.Encoding.UTF8);
 8  // 读取数据
 9  string  output = sr.ReadLine();
10  // 写入数据
11  string  input = "" ;
12  sw.WriteLine();
13  sw.Flush();

客户端和服务器的通信一般是由客户端向服务器端发请求,服务器端接受请求并处理,再将结果重新发回客户端

发送请求和应答的协议格式可以自己定义,游戏中使用的协议格式为  命令,参数1,参数2......

先看一下客户端请求登录

 1  service.SendToServer( " Login, "   +  textBoxName.Text.Trim());
 2  class  Service
 3  {
 4  ListBox listbox;
 5  StreamWriter sw;
 6  public  Service(ListBox listbox, StreamWriter sw)
 7  {
 8       this .listbox  =  listbox;
 9       this .sw  =  sw;
10  }
11  public   void  SendToServer( string  str)
12  {
13      sw.WriteLine(str);
14      sw.Flush();
15  }
16  }


服务器接受请求并处理,一般来说是根据不同的请求创建不同的线程进行处理,见本节后半部分
 1  private   void  ReceiveData( object  obj)
 2  {
 3       // User类封装了TcpClient,StreamReader和StreamWriter
 4      User user  =  (User)obj;
 5      TcpClient client  =  user.client;
 6       string  receiveString  =   null ;
 7      receiveString  =  sr.ReadLine();
 8      service.SetListBox( string .Format( " 来自{0}:{1} " , user.userName, receiveString));
 9       string [] splitString  =  receiveString.Split( ' , ' );
10       switch  (splitString[ 0 ])
11      {
12           case   " Login " :
13              user.userName  =   string .Format( " [{0}--{1}] " , splitString[ 1 ], client.Client.RemoteEndPoint);
14              service.SendToOne(user,  " Welcome " );
15               break ;
16           default :
17               break ;
18      }
19  }
20 
  

 1  class  Service
 2  {
 3           private  ListBox listbox;
 4           private   delegate   void  SetListBoxCallback( string  str);
 5           private  SetListBoxCallback setListBoxCallback;
 6           public  Service(ListBox listbox)
 7          {
 8               this .listbox  =  listbox;
 9              setListBoxCallback  =   new  SetListBoxCallback(SetListBox);
10          }
11           public   void  SetListBox( string  str)
12          {
13               if  (listbox.InvokeRequired)
14              {
15                  listbox.Invoke(setListBoxCallback, str);
16              }
17               else
18              {
19                  listbox.Items.Add(str);
20                  listbox.SelectedIndex  =  listbox.Items.Count  -   1 ;
21                  listbox.ClearSelected();
22              }
23          }
24           public   void  SendToOne(User user,  string  str)
25          {
26               try
27              {
28                  user.sw.WriteLine(str);
29                  user.sw.Flush();
30                  SetListBox( string .Format( " 向{0}发送{1} " , user.userName, str));
31              }
32               catch
33              {
34                  SetListBox( string .Format( " 向{0}发送信息失败 " , user.userName));
35              }
36          }
37   }
服务器负责监听并根据不同的用户启动不同的线程
 1  IPAddress localAddress;
 2  int  port  =   51888 ;
 3  TcpListener myListener;
 4  Service service  =   new  Service(listbox);
 5  IPAddress[] addrIP  =  Dns.GetHostAddresses(Dns.GetHostName());
 6  localAddress  =  addrIP[ 0 ];
 7  myListener  =   new  TcpListener(localAddress, port);
 8  myListener.Start();
 9  service.SetListBox( string .Format( " 开始在{0}:{1}监听客户连接 " , localAddress, port));
10  ThreadStart ts  =   new  ThreadStart(ListenClientConnect);
11  Thread myThread  =   new  Thread(ts);
12  myThread.Start();


ListenClientConnect方法
 1  while  ( true )
 2  {
 3      TcpClient newClient  =   null ;
 4       try
 5      {
 6         newClient  =  myListener.AcceptTcpClient();
 7      }
 8       catch
 9      {
10          break ;
11      }
12      User user  =   new  User(newClient);
13      userList.Add(user);
14      service.SetListBox( string .Format( " {0}进入 " , newClient.Client.RemoteEndPoint));
15      service.SetListBox( string .Format( " 当前连接用户数:{0} " ,userList.Count));
16       // basilwang 2008-09-06 to receive data from client
17      ParameterizedThreadStart pts  =   new  ParameterizedThreadStart(ReceiveData);
18      Thread threadReceive  =   new  Thread(pts);
19      threadReceive.Start(user);
20  }

此处的启用了ParameterizedThreadStart 线程处理带参数的ReceiveData方法,主要是防止同客户端传输数据的过程出现的异常不能正确处理导致线程崩溃,每一个客户端分配一个线程可以保证客户端各自的独立性;同时ParameterizedThreadStart允许传递参数。

至此我们完成了一个简单的服务器客户端应答,希望能对初学者有所帮助。

 文件下载

你可能感兴趣的:(基于TCP的网络游戏黑白棋系列(二):数据传输)