服务器端:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace multithreadservTest
{
class Threadtcpserver
{
/* 本程序中采用了多线程技术,可以应付多客户的需求。首先,程序的主线程也就是程序的入口即Main()函数,
* 当执行到Accept方法时,线程变会阻塞;当有新连接时,就创建相应的消息服务线程。而主程序则继续进行监听,
* 检查有没有新的连接进入。如果客户端有向服务器连接的请求,那么就把连接句柄传递给接收的套接字。由于线程
* 的调度和切换是非常快的,快得足以让我们分辨不出程序的运行顺序,所以从宏观上来讲,可以说程序是并行执行
* 的。但事实上,从微观的角度上说,只是cpu飞快地调度线程,让我们感觉好像可以同时接收连接和处理消息一样,
* 但在一个时刻,只有一个线程是处于运行状态的。
*/
///
/// 下面这段代码的业务逻辑是:
/// (1)创建套接字server,并将其与本地终结点iep进行绑定。然后,在13000端口上监听是否
有新的客户端进行连接
/// (2)在无限循环中有一个阻塞的方法Accept,该方法直到有新客户端连接到服务器上时,把
客户端的套接字信息传递给client对象。否则,将阻塞 直到有客户机进行连接。
/// (3)ClientThread类负责客户端与服务器端之间的通信。先把客户端的套接字句柄传递给
/// 负责消息服务的ClientThread类。然后,把ClientThread类 的ClientService方
法委托给线程,并启动线程。
///
private Socket server;
public Threadtcpserver()
{
//初始化IP地址
IPAddress local=IPAddress.Parse("192.168.5.187");
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)在构造函数中得到接收到的客户套接字client,以后就通过service句柄处理消息的接收
/// 和发送。
/// (2)ClientService方法是委托给线程的,此方法进行消息的处理工作。在这里实现的功能是,
/// 先从客户端接收一条消息,然后把这条消息转换为大写字母,并立即发送一条应答的消息,
/// 也就是所谓的echo技术,通常用来进行消息之间的传递。
/// (3)还有就是通过connections变量来记录活动的连接数。当有新增连接或断开连接的情况发
/// 生时,都会体现出connections的变化。
///
public class ClientThread
{
//connections变量表示连接数
public static int connections = 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)
{
connections++;
}
Console.WriteLine("新客户连接建立:{0}个连接数", connections);
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();
connections--;
Console.WriteLine("客户关闭连接:{0}个连接数", connections);
}
///
/// Main函数十分简单,生成和一个Threadtcpserver实例,然后构造函数就会一步一步地
/// 展开,开始执行具体的业务逻辑。
///
///
static void Main(string[] args)
{
Threadtcpserver instance = new Threadtcpserver();
}
}
}
}
客户端:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace multithreadclientTest
{
class Program
{
///
/// 本程序代码的主要功能:
/// (1)创建套接字,并通过connect方法连接到本地终结点。当连接建立以后,便可以与服务器进
/// 行通讯了。
/// (2)在客户端上等待用户输入一条消息,该消息会发送到服务器创建的消息服务线程上
/// 的ClientService 方法上进行处理。在将该消息转化为大写字母后,发还给客户端。
/// 这是一个echo技术。如果在控制台上输入exit 接断开与服务器之间的连接。
///
///
static void Main(string[] args)
{
Socket client;
byte[] buf = new byte[1024];
string input;
IPAddress local = IPAddress.Parse("192.168.5.187");
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();
}
}
}