记得张博士曾跟我说过,对于大数据量的通信软件,应该将TCP和UDP结合起来。TCP准确率高,但是传输速度低,而UDP正好相反。
现在就写写Socket通信的具体实施吧!
先说服务器端:
首先是使用Socket类型变量,启动服务器。启动需要知道本机的IP地址和一个空闲的端口号。
IP地址和端口号构成一个网络节点,使用Socket绑定网络节点即可;
public void connection() { //定义一个套接字用于监听客户端发来的信息 包含3个参数(IP4寻址协议,流式连接,TCP协议) socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //服务端发送信息 需要1个IP地址和端口号 IPAddress ipaddress = this.ipAddress; //获取文本框输入的IP地址 //将IP地址和端口号绑定到网络节点endpoint上 IPEndPoint endpoint = new IPEndPoint(ipaddress, this.portNum); //获取文本框上输入的端口号 //监听绑定的网络节点 socketWatch.Bind(endpoint); ………………
这样就创建了一个通信的端口,如果本机IP地址错误,就会报错。
当通信端口创建成功后,就需要开启监听客户端是否连接这一个功能。
socketWatch.Accept();
这就是开启监听客户端是否有连接的那句话,他的返回值是一个Socket,这个返回值是有用的需要保存下来后面使用。因此是这样写的
socConnection = socketWatch.Accept(); //socConnection 是一个Socket类型的变量
注意:监听是一个持续的过程,需单独开启一个线程,后台运行。
private void WatchConnecting() { while (true) //持续不断监听客户端发来的请求 { socConnection = socketWatch.Accept(); IsConnected = "已连接"; //注意大小写 } }
总的开启监听的代码如下:
Thread threadWatch = null; //负责监听客户端的线程 Socket socketWatch = null; //负责监听客户端的套接字 //创建一个套接字,负责和客户端通信 Socket socConnection; public Socket SocConnection { get { return socConnection; } set { socConnection = value; } } /// <summary> /// 启动服务器,开始监听客户端 /// </summary> public void connection() { //定义一个套接字用于监听客户端发来的信息 包含3个参数(IP4寻址协议,流式连接,TCP协议) socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //服务端发送信息 需要1个IP地址和端口号 IPAddress ipaddress = this.ipAddress; //获取文本框输入的IP地址 //将IP地址和端口号绑定到网络节点endpoint上 IPEndPoint endpoint = new IPEndPoint(ipaddress, this.portNum); //获取文本框上输入的端口号 //监听绑定的网络节点 socketWatch.Bind(endpoint); //将套接字的监听队列长度限制为20 socketWatch.Listen(20); //创建一个监听线程 threadWatch = new Thread(WatchConnecting); //将窗体线程设置为与后台同步 threadWatch.IsBackground = true; //启动线程 threadWatch.Start(); } private void WatchConnecting() { while (true) //持续不断监听客户端发来的请求 { socConnection = socketWatch.Accept(); IsConnected = "已连接"; //注意大小写 } }
这样,服务器就启动了,下面就在等待客户端连接了。。。
连接是否成功的标志是
socketWatch.Accept()他的返回值不是null。
也就是时刻监视socConnection 是不是null,如果不是null就证明有客户端连接,下面就是接受客户端消息的工作了。
通信工作是有Socket类型变量完成的,这个socket变量不是重新声明的而是监听成功后的返回值,否则的话,怎么能发送到已连接的客户端呢?
使用Socket.receive(arrServerRecMsg)接收消息,接收到的消息放在arrServerRecMsg缓存区中,返回接收到的字节数。byte[] arrServerRecMsg = new byte[1024 * 1024];
int length = socketServer.Receive(arrServerRecMsg);
然后将机器接收到的数组转换成人可以读的数组。
this.receiveMsg = Encoding.UTF8.GetString(arrServerRecMsg, 0, length);这样接收消息就完成了。
public void communicate() { //创建一个通信线程 ParameterizedThreadStart pts = new ParameterizedThreadStart(ServerRecMsg); Thread thr = new Thread(pts); thr.IsBackground = true; //启动线程 thr.Start(socConnection); } /// <summary> /// 接收客户端发来的消息 /// </summary> /// <param name="socketClientPara"></param> public void ServerRecMsg(object socketClientPara) { socketServer = socketClientPara as Socket; while (true) { //创建一个内存缓冲区 其大小为1024*1024字节 即1M byte[] arrServerRecMsg = new byte[1024 * 1024]; //将接收到的信息存入到内存缓冲区,并返回其字节数组的长度 int length = socketServer.Receive(arrServerRecMsg); //将机器接受到的字节数组转换为人可以读懂的字符串 this.receiveMsg = Encoding.UTF8.GetString(arrServerRecMsg, 0, length); MsgIn *= -1; } }
以上是接受消息的代码,调用的时候是调用communicate这个方法。
下面说说客户端的程序:
客户端的绑定也是
Socket.connect(endpoint),即可;endpoint = new IPEndPoint(ipaddress, this.portNum);
如果服务器端长时间没有反应,就会弹出提示对话框。
这时,正常的话就是可以连接成功,服务器端的返回值也就不再是null。服务器已经进入时刻等待接收消息的状态。
这就算是建立起了一条可以通信的通道。
发送消息的方式也很简单。就是下面的这个函数
public void sendaMsg() { //将输入的内容字符串转换为机器可以识别的字节数组 byte[] arrClientSendMsg = Encoding.UTF8.GetBytes(sendMsg); //调用客户端套接字发送字节数组 socketClient.Send(arrClientSendMsg); }
值得一提的是,里面的socketClient也是一个Socket对象。这与之前连接服务器的Socket是同一个对象。。。
这样就完成了通信。
接下来开始做客户端发送消息的程序!