首先让我们写一个C/S多线程网络程序,通过这个程序了解初学网络编程是应该注意的几个问题。
下面开始设计服务器端的业务逻辑代码:
首先,值得强调的是,要在该文件的顶端添加多线程和网络的命名空间语句:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; //可以套接字 using System.Net.Sockets; //可以使用多线程 using System.Threading; 接写来,设计类Threadtcpserver。代码如下: class Threadtcpserver { private Socket server; public Threadtcpserver() { //初始化IP地址 IPAddress local = IPAddress.Parse("127.0.0.1"); IPEndPoint iep = new IPEndPoint(local, 13000); server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //将套接字与本地终结点绑定 server.Bind(iep); //在本地13000端口号上进行监听 server.Listen(20); Console.WriteLine("等待客户机进行连接..."); while (true) { //得到包含客户端信息的套接字 Socket client = server.Accept(); //创建消息线程服务对象 ClientThread newclient = new ClientThread(client); //把ClientThread类的ClientService方法委托给线程 Thread newthread = new Thread(new ThreadStart(newclient.ClientService)); //启动消息服务进程 newthread.Start(); } } }
1.创建套接字Server,并将其与本地这结点iep进行绑定。然后,在13000端口上监听是否有新的客户端进行连接。
2.在无限循环中有一个阻塞的方法Accept(),该方法直到有新客户端连接到服务器上时,把客户端的套接字信息传递给client对象。否则,将阻塞直到有客户机进行连接。
3.ClientThread类负责处理客户端与服务器之间的通信。先把客户端的套接字句柄传递给负责消息服务的ClientThread类。然后,把ClientThread类的ClientService方法委托给线程,并启动线程。
然后开始编写ClientThread类的代码:
class ClientThread { //connection变量表示连接数 public static int connection = 0; public Socket service; int i; //构造函数 public ClientThread(Socket clientsocket) { //service对象接管对消息的控制 this.service = clientsocket; } public void ClientService() { String data = null; byte[] bytes = new byte[1024]; //如果Socket不是空,则连接数加1 if (service != null) { connection++; } Console.WriteLine("新客户建立连接:{0}个连接数", connection); while ((i=service.Receive(bytes)) != 0) { data = System.Text.Encoding.ASCII.GetString(bytes, 0, i); Console.WriteLine("收到的数据:{0}", data); //处理客户端发来的消息,这里转化为大写字母 data = data.ToUpper(); byte[] msg = System.Text.Encoding.ASCII.GetBytes(data); //发送一条答应消息 service.Send(msg); Console.WriteLine("发送的数据:{0}", data); } //关闭套接字 service.Close(); connection--; Console.WriteLine("客户关闭连接:{0}个连接数", connection); }
这段代码的业务逻辑:
1.在构造函数中得到接收到的客户端套接字client,以后就通过service句柄处理消息的接收和发送。
2.ClientService方法是委托给线程的,此方法进行消息的处理工作。在这里实现的功能是,先从客户端接收一条消息,然后把这条消息转换为大写字母,并立即发送一条应答的消息,也就是所谓的echo技术,通常用来进行消息之间的测试。
3.通过connections变量来记录活动连接数。当有新增连接或有断开连接的情况发生时,都会体现connection是的变化。
主函数代码如下:
static void Main(string[] args) { Threadtcpserver instance = new Threadtcpserver(); }
Main函数十分简单,生成一个Threadtcpsever实例,然后构造函数就会一步一步地展开,开始执行具体的业务逻辑。
编写完服务器端的程序后,只要再配置一个客户端程序即可。下面编写客户端代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { Socket client; byte[] buf = new byte[1024]; string input; IPAddress local = IPAddress.Parse("127.0.0.1"); IPEndPoint iep = new IPEndPoint(local, 13000); try { client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); client.Connect(iep); } catch (SocketException) { Console.WriteLine("无法连接到服务器!"); return; } finally { } while (true) { //在控制台上输入一条消息 input = Console.ReadLine(); //如果输入exit,可以断开服务器的连接 if (input == "exit") { break; } client.Send(Encoding.ASCII.GetBytes(input)); //得到实际收到的字节总数 int rec = client.Receive(buf); Console.WriteLine(Encoding.ASCII.GetString(buf, 0, rec)); } Console.WriteLine("断开与服务器的链接"); client.Close(); } } }
客户端是比较简单的,只有一个Main()函数。下面来分析一下这段代码的功能:
1.创建套接字,并通过connect方法连接到本地终结点。当连接建立以后,便可以与服务器进行通信了。
2.在客户端上等待用户输入一条信息,该消息会发送到服务器创建的消息服务线程上的ClientService方法进行处理。