通过本文主要向大家介绍了c#ftp客户端源代码,c#socket客户端,c#获取客户端ip地址,c#客户端连接服务器,c#客户端和服务端等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com
本文所述为基于C#实现的多人聊天程序服务端与客户端完整代码。本实例省略了结构定义部分,服务端主要是逻辑处理部分代码,因此使用时需要完善一些窗体按钮之类的。
先看服务端代码如下:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace 多人聊天程序Server端
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
// 启动服务按钮
private void button2_Click(object sender, System.EventArgs e)
{
try
{
// 必须填写端口
if(txtPort.Text == "")
{
MessageBox.Show("请先填写服务端口号!", "提示");
return;
}
Int32 port = Int32.Parse(txtPort.Text); // 获得端口号
// 创建侦听的Socket
mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint localEP = new IPEndPoint(IPAddress.Any, port);
// 将 Socket 绑定到本地的终结点上
mainSocket.Bind(localEP);
// 开始侦听,最大的连接数是 5
mainSocket.Listen(5);
// 开始一个异步操作接受客户的连接请求
mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
// 启动服务按钮不可用,停止服务按钮可用
UpdateControls(true);
}
catch(SocketException se)
{
MessageBox.Show(se.Message, "提示");
}
}
// 更新“启动服务按钮”和“停止服务”按钮的状态:是否可用;
// 注意:两个按钮的状态是互斥的
private void UpdateControls(bool onServe)
{
button2.Enabled = !onServe;
button3.Enabled = onServe;
if(onServe)
{
status.Text = "已启动服务";
}
else
{
status.Text = "未启动服务";
}
}
// 回调函数,当客户连接上时,将会被调用
public void OnClientConnect(IAsyncResult asyn)
{
try
{
// 调用EndAccept完成BeginAccept异步调用,返回一个新的Socket处理与客户的通信
Socket workerSocket = mainSocket.EndAccept(asyn);
// 增加客户数目
Interlocked.Increment(ref clientNum);
// 将 workerSocket Socket加入到 ArrayList 中
workerSocketList.Add(workerSocket);
// 发送欢迎信息给连接上服务器的客户
string msg = "欢迎客户 " + clientNum + " 登录服务器\n";
SendWelcomeToClient(msg, clientNum);
// 在线客户数目改变,必须更新客户列表
UpdateClientListControl();
// 连接上的客户接收数据
WaitForData(workerSocket, clientNum);
// 主 Socket 返回,继续等待其它的连接请求
mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
}
catch(ObjectDisposedException)
{
System.Diagnostics.Debugger.Log(0,"1","\n OnClientConnection: Socket已经关闭!\n");
}
catch(SocketException se)
{
MessageBox.Show(se.Message, "提示");
}
}
// 发送欢迎信息给客户
void SendWelcomeToClient(string msg, int clientNumber)
{
// 用UTF8格式来将string信息转化成byte数组形式
byte[] byData = System.Text.Encoding.UTF8.GetBytes(msg);
// 获得客户clientNumber对应的Socket
Socket workerSocket = (Socket)workerSocketList[clientNumber - 1];
// 将数据发给客户
workerSocket.Send(byData);
}
// 该类保存当前的socket,它的客户号还有发送给服务器的数据
public class SocketPacket
{
public System.Net.Sockets.Socket currentSocket; // 当前的Socket
public int clientNumber; // 客户号
public byte[] dataBuffer = new byte[1024]; // 发给服务器的数据
// 构造函数
public SocketPacket(System.Net.Sockets.Socket socket, int clientNumber)
{
currentSocket = socket;
this.clientNumber = clientNumber;
}
}
// 开始等待客户发送数据
public void WaitForData(System.Net.Sockets.Socket socket, int clientNumber)
{
try
{
if(pfnWorkerCallBack == null)
{
// 当连接上的客户有写的操作的时候,调用回调函数
pfnWorkerCallBack = new AsyncCallback(OnDataReceived);
}
SocketPacket socketPacket = new SocketPacket(socket, clientNumber);
socket.BeginReceive(socketPacket.dataBuffer, 0, socketPacket.dataBuffer.Length,
SocketFlags.None, pfnWorkerCallBack, socketPacket);
}
catch(SocketException se)
{
MessageBox.Show (se.Message, "提示");
}
}
// 当客户写数据时,调用以下方法
public void OnDataReceived(IAsyncResult asyn)
{
SocketPacket socketData = (SocketPacket)asyn.AsyncState ;
try
{
// EndReceive完成BeginReceive异步调用,返回客户写入流的字节数
int iRx = socketData.currentSocket.EndReceive(asyn);
// 加 1 是因为字符串以 '\0' 作为结束标志符
char[] chars = new char[iRx + 1];
// 对客户发来的信息进行UTF8解码,存入chars字符数组中
System.Text.Decoder decoder = System.Text.Encoding.UTF8.GetDecoder();
int charLen = decoder.GetChars(socketData.dataBuffer, 0, iRx, chars, 0);
System.String szData = new System.String(chars);
string msg = "客户 " + socketData.clientNumber + " 发的信息:" + szData;
// 将客户发的数据加入到信息列表中
AppendToRichEditControl(msg);
// 等待数据
WaitForData(socketData.currentSocket, socketData.clientNumber);
}
catch (ObjectDisposedException )
{
System.Diagnostics.Debugger.Log(0,"1","\nOnDataReceived: Socket已经关闭!\n");
}
catch(SocketException se)
{
if(se.ErrorCode == 10054)
{
// 将客户断开连接的信息写入信息列表中
string msg = "客户 " + socketData.clientNumber + " 已断开了连接!" + "\n";
AppendToRichEditControl(msg);
// 移走已关闭的socket
workerSocketList[socketData.clientNumber - 1] = null;
// 更新客户列表
UpdateClientListControl();
}
else
{
MessageBox.Show (se.Message, "提示");
}
}
}
// 更新信息列表,该方法可由主线程或其他工作线程所调用
private void AppendToRichEditControl(string msg)
{
// 测试看是哪个线程调用了该方法
if (InvokeRequired)
{
// We cannot update the GUI on this thread.
// All GUI controls are to be updated by the main (GUI) thread.
// Hence we will use the invoke method on the control which will
// be called when the Main thread is free
// Do UI update on UI thread
object[] pList = {msg};
txtRecvMsg.BeginInvoke(new UpdateRichEditCallback(OnUpdateRichEdit), pList);
}
else
{
// 创建该控件的主线程直接更新信息列表
OnUpdateRichEdit(msg);
}
}
// 添加信息到 txtRecvMsg 中
private void OnUpdateRichEdit(string msg)
{
// txtRecvMsg.AppendText(msg);
txtRecvMsg.Text = txtRecvMsg.Text + msg;
}
// 更新客户列表
private void UpdateClientListControl()
{
if (InvokeRequired) // Is this called from a thread other than the one created
// the control
{
clientList.BeginInvoke(new UpdateClientListCallback(UpdateClientList), null);
}
else
{
// 创建该控件的主线程直接更新信息列表
UpdateClientList();
}
}
// 更新客户列表
void UpdateClientList()
{
clientList.Items.Clear(); // 清空客户列表
for(int i = 0; i < workerSocketList.Count; i++)
{
// 加1,是因为数组从下标0开始,而我们的客户标号是从1开始
string clientKey = Convert.ToString(i + 1);
Socket workerSocket = (Socket)workerSocketList[i];
if(workerSocket != null)
{
// 将连接着服务器的客户添加到客户列表中
if(workerSocket.Connected)
{
clientList.Items.Add(clientKey);
}
}
}
}
// 停止服务按钮
private void button3_Click(object sender, System.EventArgs e)
{
CloseSockets();
UpdateControls(false);
// 更新客户列表
UpdateClientListControl();
}
// 发送信息按钮
private void button1_Click(object sender, System.EventArgs e)
{
// 如果在线客户列表不为空,则允许发送信息
if (clientList.Items.Count != 0 )
{
try
{
string msg = txtSendMsg.Text;
msg = "服务器信息: " + msg + "\n";
byte[] byData = System.Text.Encoding.UTF8.GetBytes(msg);
Socket workerSocket = null;
for(int i = 0; i < workerSocketList.Count; i++)
{
workerSocket = (Socket)workerSocketList[i];
if(workerSocket!= null)
{
// 发给所有连接上服务器的客户
if(workerSocket.Connected)
{
workerSocke

