二 C# Socket通信模式

  Socket通信有两种模式:阻塞模式和非阻塞模式。

  1:阻塞模式

  所谓阻塞模式,就是开启一个线程一直保持侦听状态(通过while(true)循环),这样该线程将一直在这个循环里运行,不会退出,因此该线程将被该循环所阻塞,是为阻塞模式。使用该模式进行通信时,必须开启一个新线程,不能将其置于主线程中,否则主线程什么事都干不了。

  阻塞模式通信中又分为两种方式——重连接和持续连接。重连接就是发送端每次发送信息时,重新与接收端进行连接;而持续连接则是发送端初始化时便与接收端进行连接,并且此后一直保持连接。这两种连接方式在编程上的区别主要体现在接收端——对于前者,接收端的Socket accept = listener.Accept()必须写在while(true)循环里面;而对于后者,则必须写在循环外面。这一点对于新手很重要,我开始接触套接字编程时,由于不知道有这么一个区别存在,所以总是不知道错误到底出现在哪里!

  下面举例说明阻塞模式下的这两种编程方式。

  1.1 阻塞模式之重连接方式

  发送端:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace DelTest
ExpandedBlockStart.gifContractedBlock.gif
{
    
public partial class Form1 : Form
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
public Form1()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            InitializeComponent();
        }


        
private void Form1_Load(object sender, EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{}

        
        
private void button1_Click(object sender, EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            Socket _sender 
= null;//每次发送时,都实例化一个套接字,并与客户端进行连接
            
try
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _sender 
= new Socket(
                    AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                _sender.Connect(IPAddress.Parse(
"192.168.0.53"), 2000);
                
if (_sender.Connected)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
byte[] sends = Encoding.Unicode.GetBytes(this.textBox1.Text);
                    _sender.Send(sends);
                }

            }

            
catch (Exception ee)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{ }
            
finally
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _sender.Close();
            }

        }

    }

}

  

          

  

 

  接收端:

using System;
using System.Collections.Generic;
using System.Text;

using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace DelTest_Rec
ExpandedBlockStart.gifContractedBlock.gif
{
    
class Program
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
static void Main(string[] args)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            Test t 
= new Test();
            t.Listen();

            Console.ReadLine();
        }

    }


    
class Test
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
delegate void ThreadMethod(object obj);
        ThreadMethod _tm 
= null;

        
private Socket _listener = null;
        
private string _localIP = null;

        
public void Listen()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            _tm 
= Show;

            _localIP 
= Dns.GetHostAddresses(Dns.GetHostName())[0].ToString();
            _listener 
= new Socket(
                AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _listener.Bind(
new IPEndPoint(IPAddress.Parse(_localIP), 2000));
            _listener.Listen(
50);

            Thread thread 
= new Thread(new ThreadStart(Receive));
            thread.IsBackground 
= true;
            thread.Start();
        }


        
private void Receive()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
try
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
while (true)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    Socket accept 
= _listener.Accept();//发送端为重连接,故本语句必须放在while循环里面
                    
byte[] rec = new byte[4999];
                                        accept.Receive(rec);
                    
string recStr = Encoding.Unicode.GetString(rec);

                    _tm(recStr);
                }

            }

            
catch (Exception ee)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
            }

        }


        
private void Show(object obj)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            Console.WriteLine(obj.ToString());
        }

    }

}

  1.2 阻塞模式之重连接方式

  这种模式需要注意的是:接收端应用程序必须先开启,然后才能运行发送端程序。

  发送端:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace DelTest
ExpandedBlockStart.gifContractedBlock.gif
{
    
public partial class Form1 : Form
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
private Socket _sender = null;
        
        
private void Form1_Load(object sender, EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//程序启动时便与远程进行连接
            _sender = Connect("192.168.0.53"2000);
        }

        
        
private void button1_Click(object sender, EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
try
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
if (_sender.Connected)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
byte[] sends = Encoding.Unicode.GetBytes(this.textBox1.Text);
                    _sender.Send(sends);
                }

            }

            
catch (Exception ee)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{}
        }


ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 与远程进行连接
        
/// </summary>
        
/// <param name="ip">远程IP地址</param>
        
/// <param name="port">远程侦听端口</param>
        
/// <returns></returns>

        private Socket Connect(string ip, int port)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            IPAddress ipa 
= IPAddress.Parse(ip);
            IPEndPoint ipe 
= new IPEndPoint(ipa, port);
            Socket sender 
= new Socket(
                AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            
try
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                sender.Connect(ipe);
            }

            
catch (SocketException se)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return null;
            }

            
return sender;
        }


        
public Form1()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            InitializeComponent();
        }

    }

}

  接收端:

using System;
using System.Collections.Generic;
using System.Text;

using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace DelTest_Rec
ExpandedBlockStart.gifContractedBlock.gif
{
    
class Program
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
static void Main(string[] args)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            Test t 
= new Test();
            t.Listen();

            Console.ReadLine();
        }

    }


    
class Test
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
delegate void ThreadMethod(object obj);
        ThreadMethod _tm 
= null;

        
private Socket _listener = null;
        
private string _localIP = null;

        
public void Listen()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            _tm 
= Show;

            _localIP 
= Dns.GetHostAddresses(Dns.GetHostName())[0].ToString();
            _listener 
= new Socket(
                AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _listener.Bind(
new IPEndPoint(IPAddress.Parse(_localIP), 2000));
            _listener.Listen(
50);

            Thread thread 
= new Thread(new ThreadStart(Receive));
            thread.IsBackground 
= true;
            thread.Start();
        }


        
private void Receive()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
try
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                Socket accept 
= _listener.Accept();//发送端为持续连接,本语句必须放在while循环外面
                while (true)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
byte[] rec = ReceiveVarData(accept);
                    
string recStr = Encoding.Unicode.GetString(rec);

                    _tm(recStr);
                }

            }

            
catch (Exception ee)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{

            }

        }


        
private void Show(object obj)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            Console.WriteLine(obj.ToString());
        }

    }

}

  在实际项目中,一般采用持续连接,这是因为这里的套接字所采用的传输协议是TCP/IP协议,当与远程建立连接时,需要经过三次握手,一旦出现异常,通常都会在30秒以后才能确定有没有与远程连接上,因此一般都是一次连接多次使用,而不是使用一次连接一次。一般而言,发送端需要开启一个线程专门与远程保持连接;接收端也开启一个线程专门侦听远程套接字。

  2:非阻塞模式

  所谓非阻塞模式,就是接收端不使用while循环来一直保持侦听,此时,接收端必须明确知道发送端在什么时间发送套接字,这种模式一般不会使用。下面举一例说明:

  发送端:

        private void Form1_Load(object sender, EventArgs e)
ExpandedBlockStart.gifContractedBlock.gif        
{
            IPAddress ipa 
= IPAddress.Parse(ip);
            IPEndPoint ipe 
= new IPEndPoint(ipa, port);
            Socket sender 
= new Socket(
                AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            
try
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                sender.Connect(ipe);
                sender.Send(Encoding.Unicode.GetBytes(
"hello everyone!"));
            }

            
catch (SocketException se)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{}
        }

  接收端:

using System;
using System.Collections.Generic;
using System.Text;

using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace DelTest_Rec
ExpandedBlockStart.gifContractedBlock.gif
{
    
class Program
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
static void Main(string[] args)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            Test t 
= new Test();
            t.Listen();

            Console.ReadLine();
        }

    }


    
class Test
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
delegate void ThreadMethod(object obj);
        ThreadMethod _tm 
= null;

        
private Socket _listener = null;
        
private string _localIP = null;

        
public void Listen()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            _tm 
= Show;

            _localIP 
= Dns.GetHostAddresses(Dns.GetHostName())[0].ToString();
            _listener 
= new Socket(
                AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _listener.Bind(
new IPEndPoint(IPAddress.Parse(_localIP), 2000));
            _listener.Listen(
50);

                        
//非阻塞模式下,连多线程也省了,开启线程也没意义
            Socket accept = _listener.Accept();
                        
byte[] rec = ReceiveVarData(accept);
            
string recStr = Encoding.Unicode.GetString(rec);
                        Console.WriteLine(obj.ToString());
        }

    }

}

 

  3:Socket编程中注意点

  (1)发送端和接收端所使用的编码必须一致;

  (2)注意阻塞模式中还存在如本例所说的两种套接字通信方式;

  (3)在发送端与远程建立套接字连接之前,必须运行接收端进行侦听,否则将报错;

  (4)在项目中需要引入3个空间:using System.Net;
                
using System.Net.Sockets;
                
using System.Threading;

  

  

c# socket通信的问题

08-20

,我的服务端在运行,并且与客户端通信,但是还有的客户端连不上.rn服务端关键代码:rn private void socketbind()rn rn tryrn rn string ip = pxl.serverip;rn IPAddress ipadd = IPAddress.Parse(ip);rn IPEndPoint iep = new IPEndPoint(ipadd, pxl.serverport);rn ssk = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);rn ssk.Bind(iep);rn ssk.Listen(10);rn //AcceptConnection();rn log.Info("服务已启动!");rn thread = new Thread(AcceptConnection);rn thread.IsBackground = true;rn thread.Start();rn rn catch (Exception ex)rn rn log.Error(ex.ToString());rn rn rnrnvoid AcceptConnection()rn rn Socket msgsok = null;rn while (true)rn rn tryrn rn msgsok = ssk.Accept();rn log.Info(msgsok.RemoteEndPoint.ToString() + "已经连接!");rn NetworkStream ns = new NetworkStream(msgsok);rn tryrn rn #region //接收用户标识的长度,最多3位,最大值999rn byte[] bt = new byte[3];rn log.Info("接收身份信息!");rn tryrn rn ns.Read(bt, 0, bt.Length);rn rn catchrn rn log.Info(msgsok.RemoteEndPoint.ToString()+"发生异常,关闭连接并释放资源!");rn closeConnection(msgsok, ns);rn continue;rn rnrn string str = System.Text.Encoding.UTF8.GetString(bt);rn int reclen = int.Parse(str);rn log.Info("读取到身份信息长度" + str);rn #endregionrn #region //接收用户标识rn bt = new byte[reclen];rn //msgsok.Receive(bt);rn tryrn rn ns.Read(bt, 0, bt.Length);rn rn catchrn rn log.Info(msgsok.RemoteEndPoint.ToString() + "接收用户标识发生异常,关闭连接并释放资源!");rn closeConnection(msgsok, ns);rn continue;rn rn str = System.Text.Encoding.UTF8.GetString(bt);rn string[] ids = str.Split(',');rn #endregionrn Client client = new Client();rn client.ns = ns;rn client.id = ids[0];rn client.name = ids[1];rn client.weighbridgeid = ids[2];rn client.weighbridge = ids[3];rn client.ssk = msgsok;rn client.set();rn log.Info(client.name + "," + client.id + "--" + client.weighbridge + "," + client.weighbridgeid + "已经连接!");rn tryrn rn //移去同一个IP地址下的其它连接rn this.removeSameIPSession(client);rn rn catchrn rn rn //将连接client信息存入sessionrn InsertSession(client);rn Thread th1 = new Thread(WatchMsg);rn th1.IsBackground = true;rn th1.Start(client);rn rn catch (Exception ex)rn rn log.Error(ex.ToString());rn tryrn rn Thread.CurrentThread.Abort();rn rn catchrn rn log.Info("中止AcceptConnection");rn rn finallyrn rn Thread.Sleep(5000);rn Thread th = new Thread(AcceptConnection);rn th.IsBackground = true;rn th.Start();rn rn rn rn rn catch(Exception ex)rn rn log.Error(ex.ToString());rn rn rn rnrn客户端连接代码:rnprivate void connectServer()rn rn string ip = pxl.serverip;rn int port = pxl.serverport;rn IPAddress ipadd = IPAddress.Parse(ip);rn IPEndPoint iep = new IPEndPoint(ipadd, port);rn HelperByte hb = new HelperByte();rn tryrn rn //msgsok = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);rn MyVariable mv = new MyVariable();rn mv.set();rn sok = mv.c;rn sok.Connect(iep);rn // this.sok = msgsok;rn String str = Configuration.GetAppConfig("ClientID") + "," + Configuration.GetAppConfig("ClientName") + "," + Configuration.GetAppConfig("WeighBridgeID") + "," + Configuration.GetAppConfig("WeighBridge");rn byte[] bt = System.Text.Encoding.UTF8.GetBytes(str);rn //获得rn string len = hb.calnum(bt, 3);rn byte[] btlen = System.Text.Encoding.UTF8.GetBytes(len);rn //合并长度和身份信息rn byte[] sendbt = hb.copybyte(btlen, bt);rn ns = new NetworkStream(sok);rn lock (ns)rn rn ns.Write(sendbt, 0, sendbt.Length);rn rn log.Info("已经连接上服务器!");rn Client client = new Client();rn client.ssk = sok;rn client.ns = ns;rn Thread th = new Thread(recMsg);rn th.IsBackground = true;rn th.Start(client);rn rn catch (Exception ex)rn rn log.Error(ex.ToString());rn //log.Info(ex.ToString());rn tryrn rn Thread.CurrentThread.Abort();rn rn catchrn rn log.Info("发生意外,正在中止当前线程!");rn rn finallyrn rn Thread.Sleep(5000);rn rn tryrn rn this.restart();rn rn catchrn rn rn rn rn rn rnrn一部分客户端正常运行,还有一部分客户端连不上,但是有可能过一段时间又连上了,请高手帮忙 论坛

没有更多推荐了,返回首页