读书人

关于客户端与服务器通信有关问题(多线

发布时间: 2012-08-14 10:39:57 作者: rapoo

关于客户端与服务器通信问题(多线程)
现就客户端和服务器通信进行讨论:
进行测试的时候客户端LOGIN,服务器端没反应。跟踪调试两个程序之后,发现len = Stream.Read(buff,0,buff.Length);好像值是空的。到网上查,网友说是线程在程序结束时已经被关闭了!所以服务器的OK命令根本传不到客户端进行处理,也就是说流通道根本没有数据?而且调试程序的时候有提示由于以前的函数求值超时,函数求值被禁用。必须继续执行才能重新启用函数求值。
求救!!!!!!
还有一点客户端和服务端能在同一台机器上面测试吗?
服务器主要代码如下:

C# code
        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");                }            }        }


其中服务器端还包含了Client类,它封装了客户端的信息和连接,每有一个客户进入聊天室,就创建一个Client对象,用于保存该用户的信息并接收用户的数据和发送信息到客户端,该类主要代码如下
C# code
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);        }    }} 


——————————————————————————————————————————————————————
客户端主要代码如下:
C# code
        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());            }        }



[解决办法]
本人菜鸟,正好也在做客户端的socket通信,看了下楼主代码,提个意见,不一定对啊

探讨
现就客户端和服务器通信进行讨论:
进行测试的时候客户端LOGIN,服务器端没反应。跟踪调试两个程序之后,发现len = Stream.Read(buff,0,buff.Length);好像值是空的。到网上查,网友说是线程在程序结束时已经被关闭了!所以服务器的OK命令根本传不到客户端进行处理,也就是说流通道根本没有数据?而且调试程序的时候有提示由于以前的函数求值超时,函数求值被禁用。必须继续执行才能重新启用函数求值。
求救!!!!!!
还有一点客户端和服务端能在同一台机器上面测试吗?
服务器主要代码如下:
C# codeprivatevoid 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");
}
}//在新的线程中的操作,它主要用于当接收到一个客户端请求时,确认与客户端的链接//并且立刻启动一个新的线程来处理和该客户端的信息交互privatevoid 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");
}
}
}

其中服务器端还包含了Client类,它封装了客户端的信息和连接,每有一个客户进入聊天室,就创建一个Client对象,用于保存该用户的信息并接收用户的数据和发送信息到客户端,该类主要代码如下
C# codeusing 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
{privatestring name;private Socket currentSocket=null;privatestring ipAddress;private ClientSeverForm server;//保存当前连接的状态//closed -->connected ->>closedprivatestring state="CLOSED";public Client(ClientSeverForm server, Socket clientSocket)
{this.server= server;this.currentSocket= clientSocket;
ipAddress= getRemoteIpAddress();
}privatevoid SendToClient(Client client,string msg)
{
System.Byte[] message= System.Text.Encoding.Default.GetBytes(msg.ToCharArray());
client.CurrentSocket.Send(message, message.Length,0);
}//serviceClient方法用于和客户端进行数据通信,包括接受客户端的请求,//它根据不同的请求命令执行相应的操作,并将处理结果返回到客户端publicvoid ServiceClient()
{string[] tokens=null;byte[] buff=newbyte[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")
{
......
}elseif (tokens[0]=="LIST")
{
......
}elseif (tokens[0]=="CHAT")
{
......
}elseif (tokens[0]=="PRIV")
{
......
}elseif (tokens[0]=="EXIT")
{
......
}
Thread.Sleep(200);
}
}
}
——————————————————————————————————————————————————————
客户端主要代码如下:
C# codeprivatevoid 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);
}
}privatevoid ServerResponse()
{//定义了一个byte数组,用于接收从服务器端发来的数据//每次所能接受的数据包的最大长度为1024个字节byte[] buff=newbyte[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")
{
......
}elseif (tokens[0].ToUpper()=="ERR")
{
......
}elseif (tokens[0]=="LIST")
{
......
}elseif (tokens[0]=="JOIN")
{
......
}elseif (tokens[0]=="QUIT")
{
......

}else
{
add(msg);
}
tcpClient.Close();
}catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}


[解决办法]
能在同一服务器测试

[解决办法]
可以同时测试,但一般是先开服务器,再开客户端。服务器要保持连接状态
[解决办法]
我来看看,学习学习
[解决办法]
首先程序结构上的设计实在不敢恭维。
Thread thread = new Thread(new ThreadStart(this.StartSocketListen));



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 讨论。

读书人网 >C#

热点推荐