关于客户端与服务器通信问题(多线程)
现就客户端和服务器通信进行讨论:
进行测试的时候客户端LOGIN,服务器端没反应。跟踪调试两个程序之后,发现len = Stream.Read(buff,0,buff.Length);好像值是空的。到网上查,网友说是线程在程序结束时已经被关闭了!所以服务器的OK命令根本传不到客户端进行处理,也就是说流通道根本没有数据?而且调试程序的时候有提示由于以前的函数求值超时,函数求值被禁用。必须继续执行才能重新启用函数求值。
求救!!!!!!
还有一点客户端和服务端能在同一台机器上面测试吗?
服务器主要代码如下:
private void btnSocketStart_Click(object sender, EventArgs e) { int port = getValidPort(tbSocketPort.Text); if (port < 0) { return; } string ip = this.getIPAddress(); try { IPAddress ipAdd = IPAddress.Parse(ip); //创建服务器套接字 listener = new TcpListener(ipAdd, port); //开始监听服务器端口 listener.Start(); this.rbSocketMsg.AppendText("Socket服务器已经启动,正在监听" + ip + "端口号" + this.tbSocketPort.Text + "\n"); //启动一个新的线程,执行方法this.StartSocketListen //以便在一个独立的进程中执行确认与客户端Socket连接的操作 ClientSeverForm.SocketServiceFlag = true; Thread thread = new Thread(new ThreadStart(this.StartSocketListen)); thread.Start(); this.btnSocketStart.Enabled = false; this.btnSocketStop.Enabled = true; } catch (Exception ex)//????? { this.rbSocketMsg.AppendText(ex.Message.ToString() + "\n"); } } //在新的线程中的操作,它主要用于当接收到一个客户端请求时,确认与客户端的链接 //并且立刻启动一个新的线程来处理和该客户端的信息交互 private void StartSocketListen() { while (ClientSeverForm.SocketServiceFlag) { try { //当接收到一个客户端请求时,确认与客户端的链接 if (listener.Pending()) { Socket socket = listener.AcceptSocket(); if (clients.Count >= MAXNUM) { this.rbSocketMsg.AppendText("已经到达了最大连接数:" + MAXNUM + ",拒绝新的连接\n"); socket.Close(); } else { //启动一个新的线程 //执行方法this.ServiceClient,处理用户相应的请求 Client client = new Client(this, socket); Thread clientService = new Thread(new ThreadStart(client.ServiceClient)); clientService.Start(); } } Thread.Sleep(200); } catch (Exception ex) { this.rbSocketMsg.AppendText(ex.Message.ToString() + "\n"); } } }
using System;using System.Collections.Generic;using System.Text;//以下为程序引用到的库文件using System.Net;using System.Net.Sockets;using System.Threading;using System.Collections;namespace chatserver{ class Client { private string name; private Socket currentSocket = null; private string ipAddress; private ClientSeverForm server; //保存当前连接的状态 //closed -->connected ->>closed private string state = "CLOSED"; public Client(ClientSeverForm server, Socket clientSocket) { this.server = server; this.currentSocket = clientSocket; ipAddress = getRemoteIpAddress(); } private void SendToClient(Client client, string msg) { System.Byte[] message = System.Text.Encoding.Default.GetBytes(msg.ToCharArray()); client.CurrentSocket.Send(message, message.Length, 0); } //serviceClient方法用于和客户端进行数据通信,包括接受客户端的请求, //它根据不同的请求命令执行相应的操作,并将处理结果返回到客户端 public void ServiceClient() { string[] tokens = null; byte[] buff = new byte[1024]; bool keepConnect = true; //用循环来不断地与客户端进行交互,直至到客户端发出“EXIT”命令, //将KeepConnect置为false,退出循环,关闭连接,并中止当前线程 while (keepConnect && ClientSeverForm.SocketServiceFlag) { tokens = null; try { if (currentSocket == null || currentSocket.Available < 1) { Thread.Sleep(300); continue; } //接收数据并存入buff数组中 int len = currentSocket.Receive(buff); //将字符数组转化为字符串 string clientCommand = System.Text.Encoding.Default.GetString(buff, 0, len); //tokens[0]中保存了命令标识符(conn,chat,priv,list或exit) tokens = clientCommand.Split(new Char[] { '|' }); if (tokens == null) { Thread.Sleep(200); continue; } } catch (Exception e) { server.updateUI("发生异常:" + e.ToString()) ; } } if (tokens[0] == "CONN") { ...... } else if (tokens[0] == "LIST") { ...... } else if (tokens[0] == "CHAT") { ...... } else if (tokens[0] == "PRIV") { ...... } else if (tokens[0] == "EXIT") { ...... } Thread.Sleep(200); } }}
private void btnLogin_Click(object sender, EventArgs e) { if (state == "CONNECTED") { return; } if (this.tbUserName.Text.Length == 0) { MessageBox.Show("请输入您的昵称!", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); this.tbUserName.Focus(); return; } try { //创建一个客户端套接字,它是Login的一个公共的属性, //将被传递给ChatClient窗体 tcpClient = new TcpClient(); tcpClient.Connect(IPAddress.Parse(txtHost.Text), Int32.Parse(txtPort.Text)); //获得与服务器数据交互的流通道 Stream = tcpClient.GetStream(); //启动一个新的线程,执行方法this.ServerResponse() //以便来响应从服务器发回的信息 Thread thread = new Thread(new ThreadStart(this.ServerResponse)); thread.Start(); string cmd = "CONN|" + this.tbUserName.Text + "|"; //将字符串转化为字符数组 Byte[] outbytes = System.Text.Encoding.Default.GetBytes(cmd.ToCharArray()); Stream.Write(outbytes, 0, outbytes.Length); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void ServerResponse() { //定义了一个byte数组,用于接收从服务器端发来的数据 //每次所能接受的数据包的最大长度为1024个字节 byte[] buff = new byte[1024]; string msg = null; int len = 0; string[] tokens = null; try { if (!Stream.CanRead) { return; } stopFlag = false; while (!stopFlag) { //从流中得到数据,并存入到buff字符数组中 len = Stream.Read(buff, 0, buff.Length); if (len < 1) { // Thread.Sleep(200); // continue; MessageBox.Show(len.ToString()); } //将字符数组转化为字符串 msg = System.Text.Encoding.Default.GetString(buff, 0, len); msg.Trim(); tokens = msg.Split(new Char[] { '|' }); //tokens[0]中保存了命令标识符 } if (tokens[0].ToUpper() == "OK") { ...... } else if (tokens[0].ToUpper() == "ERR") { ...... } else if (tokens[0] == "LIST") { ...... } else if (tokens[0] == "JOIN") { ...... } else if (tokens[0] == "QUIT") { ...... } else { add(msg); } tcpClient.Close(); } catch (Exception e) { MessageBox.Show(e.ToString()); } }
thread.Start();
这里肯定有问题,怎么能实时监听用户的接入???
正确的方法应该是使用异步回调
下面是我曾经写的一个服务器里面的代码,你参考一下:
/// <summary>
/// 启动服务
/// </summary>
/// <returns></returns>
public void Start()
{
try
{
this._accountManager = new AccountManager();
if (this._accountManager.Load())
{
IPEndPoint endPoin = new IPEndPoint(IPAddress.Any, 3568);
this.Listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
this.Listener.Bind(endPoin);
this.Listener.Listen(256);
this.Listener.BeginAccept(new AsyncCallback(Accept), this.Listener);
}
else
{
System.Windows.Forms.MessageBox.Show("原因:未能加载账户列表。", "启动服务失败!", System.Windows.Forms.MessageBoxButtons.OK);
return;
}
}
catch (Exception ex) { }
}
/// <summary>
/// 请求连接进入
/// </summary>
/// <param name="ar"></param>
private void Accept(IAsyncResult ar)
{
try
{
if (this.Listener != null)
{
Connection conn = new Connection(this, Listener.EndAccept(ar));
this._Connections.Add(conn);
//继续监听
this.Listener.BeginAccept(new AsyncCallback(Accept), this.Listener);
}
}
catch (Exception ex) { }
}
[解决办法]
具体的可以加我msn:sugarche@hotmail.com 讨论。