用C#写的 一个简单的TCP通信,主要的功能有:

(1) 多个客户端与服务器间的数据交流
(2)可以实现群发的功能
(3)客户端与服务端可以进行文件的传输

主要用到的知识: TCP里的 socket 、多线程 Thread
下面分别是服务端和客户端的代码:
服务端代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.IO;

namespace A
{
public partial class frm_server : Form
{
public frm_server()
{
InitializeComponent();
TextBox.CheckForIllegalCrossThreadCalls = false;
}

    Thread threadWatch = null; // 负责监听客户端连接请求的 线程;Socket socketWatch = null;Dictionary<string, Socket> dict = new Dictionary<string, Socket>();Dictionary<string, Thread> dictThread = new Dictionary<string, Thread>();private void btnBeginListen_Click(object sender, EventArgs e){// 创建负责监听的套接字,注意其中的参数;socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);// 获得文本框中的IP对象;IPAddress address = IPAddress.Parse(txtIp.Text.Trim());// 创建包含ip和端口号的网络节点对象;IPEndPoint endPoint = new IPEndPoint(address, int.Parse(txtPort.Text.Trim()));try{// 将负责监听的套接字绑定到唯一的ip和端口上;socketWatch.Bind(endPoint);}catch (SocketException se){MessageBox.Show("异常:"+se.Message);return;}// 设置监听队列的长度;socketWatch.Listen(10);// 创建负责监听的线程;threadWatch = new Thread(WatchConnecting);threadWatch.IsBackground = true;threadWatch.Start();ShowMsg("服务器启动监听成功!");//}}/// <summary>/// 监听客户端请求的方法;/// </summary>void WatchConnecting(){while (true)  // 持续不断的监听客户端的连接请求;{// 开始监听客户端连接请求,Accept方法会阻断当前的线程;Socket sokConnection = socketWatch.Accept(); // 一旦监听到一个客户端的请求,就返回一个与该客户端通信的 套接字;// 想列表控件中添加客户端的IP信息;lbOnline.Items.Add(sokConnection.RemoteEndPoint.ToString());// 将与客户端连接的 套接字 对象添加到集合中;dict.Add(sokConnection.RemoteEndPoint.ToString(), sokConnection);ShowMsg("客户端连接成功!");Thread thr = new Thread(RecMsg);thr.IsBackground = true;thr.Start(sokConnection);dictThread.Add(sokConnection.RemoteEndPoint.ToString(), thr);  //  将新建的线程 添加 到线程的集合中去。}}void RecMsg(object sokConnectionparn){Socket sokClient = sokConnectionparn as Socket;while (true){// 定义一个2M的缓存区;byte[] arrMsgRec = new byte[1024 * 1024 * 2];// 将接受到的数据存入到输入  arrMsgRec中;int length = -1;try{length = sokClient.Receive(arrMsgRec); // 接收数据,并返回数据的长度;}catch (SocketException se){ShowMsg("异常:" + se.Message);// 从 通信套接字 集合中删除被中断连接的通信套接字;dict.Remove(sokClient.RemoteEndPoint.ToString());// 从通信线程集合中删除被中断连接的通信线程对象;dictThread.Remove(sokClient.RemoteEndPoint.ToString());// 从列表中移除被中断的连接IPlbOnline.Items.Remove(sokClient.RemoteEndPoint.ToString());break;}catch (Exception e){ShowMsg("异常:" + e.Message);// 从 通信套接字 集合中删除被中断连接的通信套接字;dict.Remove(sokClient.RemoteEndPoint.ToString());// 从通信线程集合中删除被中断连接的通信线程对象;dictThread.Remove(sokClient.RemoteEndPoint.ToString());// 从列表中移除被中断的连接IPlbOnline.Items.Remove(sokClient.RemoteEndPoint.ToString());break;}if (arrMsgRec[0] == 0)  // 表示接收到的是数据;{string strMsg = System.Text.Encoding.UTF8.GetString(arrMsgRec,1, length-1);// 将接受到的字节数据转化成字符串;ShowMsg(strMsg);}if (arrMsgRec[0] == 1) // 表示接收到的是文件;{SaveFileDialog sfd = new SaveFileDialog();if (sfd.ShowDialog(this) == System.Windows.Forms.DialogResult.OK){// 在上边的 sfd.ShowDialog() 的括号里边一定要加上 this 否则就不会弹出 另存为 的对话框,而弹出的是本类的其他窗口,,这个一定要注意!!!【解释:加了this的sfd.ShowDialog(this),“另存为”窗口的指针才能被SaveFileDialog的对象调用,若不加thisSaveFileDialog 的对象调用的是本类的其他窗口了,当然不弹出“另存为”窗口。】string fileSavePath = sfd.FileName;// 获得文件保存的路径;// 创建文件流,然后根据路径创建文件;using (FileStream fs = new FileStream(fileSavePath, FileMode.Create)){fs.Write(arrMsgRec, 1, length - 1);ShowMsg("文件保存成功:" + fileSavePath);}}}}     }void ShowMsg(string str){txtMsg.AppendText(str + "\r\n");}// 发送消息private void btnSend_Click(object sender, EventArgs e){string strMsg = "服务器" + "\r\n" + "   -->" + txtMsgSend.Text.Trim() + "\r\n";byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg); // 将要发送的字符串转换成Utf-8字节数组;byte[] arrSendMsg=new byte[arrMsg.Length+1];arrSendMsg[0] = 0; // 表示发送的是消息数据Buffer.BlockCopy(arrMsg, 0, arrSendMsg, 1, arrMsg.Length);string strKey = "";strKey = lbOnline.Text.Trim();if (string.IsNullOrEmpty(strKey))   // 判断是不是选择了发送的对象;{MessageBox.Show("请选择你要发送的好友!!!");}else{dict[strKey].Send(arrSendMsg);// 解决了 sokConnection是局部变量,不能再本函数中引用的问题;ShowMsg(strMsg);txtMsgSend.Clear();}}/// <summary>/// 群发消息/// </summary>/// <param name="sender"></param>/// <param name="e">消息</param>private void btnSendToAll_Click(object sender, EventArgs e){string strMsg = "服务器" + "\r\n" + "   -->" + txtMsgSend.Text.Trim() + "\r\n";byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg); // 将要发送的字符串转换成Utf-8字节数组;foreach (Socket s in dict.Values){s.Send(arrMsg);}ShowMsg(strMsg);txtMsgSend.Clear();ShowMsg(" 群发完毕~~~");}// 选择要发送的文件private void btnSelectFile_Click_1(object sender, EventArgs e){OpenFileDialog ofd = new OpenFileDialog();ofd.InitialDirectory = "D:\\";if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK){txtSelectFile.Text = ofd.FileName;}}// 文件的发送private void btnSendFile_Click_1(object sender, EventArgs e){if (string.IsNullOrEmpty(txtSelectFile.Text)){MessageBox.Show("请选择你要发送的文件!!!");}else{// 用文件流打开用户要发送的文件;using (FileStream fs = new FileStream(txtSelectFile.Text, FileMode.Open)){string fileName=System.IO.Path.GetFileName(txtSelectFile.Text);string fileExtension=System.IO.Path.GetExtension(txtSelectFile.Text);string strMsg = "我给你发送的文件为: "+fileName+fileExtension+"\r\n";byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg); // 将要发送的字符串转换成Utf-8字节数组;byte[] arrSendMsg = new byte[arrMsg.Length + 1];arrSendMsg[0] = 0; // 表示发送的是消息数据Buffer.BlockCopy(arrMsg, 0, arrSendMsg, 1, arrMsg.Length);bool fff = true;string strKey = "";strKey = lbOnline.Text.Trim();if (string.IsNullOrEmpty(strKey))   // 判断是不是选择了发送的对象;{MessageBox.Show("请选择你要发送的好友!!!");}else{dict[strKey].Send(arrSendMsg);// 解决了 sokConnection是局部变量,不能再本函数中引用的问题;byte[] arrFile = new byte[1024 * 1024 * 2];int length = fs.Read(arrFile, 0, arrFile.Length);  // 将文件中的数据读到arrFile数组中;byte[] arrFileSend = new byte[length + 1];arrFileSend[0] = 1; // 用来表示发送的是文件数据;Buffer.BlockCopy(arrFile, 0, arrFileSend, 1, length);// 还有一个 CopyTo的方法,但是在这里不适合; 当然还可以用for循环自己转化;//  sockClient.Send(arrFileSend);// 发送数据到服务端;dict[strKey].Send(arrFileSend);// 解决了 sokConnection是局部变量,不能再本函数中引用的问题;txtSelectFile.Clear(); }}}txtSelectFile.Clear();}}

}
客户端代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

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

namespace B
{
public partial class frmClient : Form
{
public frmClient()
{
InitializeComponent();
TextBox.CheckForIllegalCrossThreadCalls = false;
}

    Thread threadClient = null; // 创建用于接收服务端消息的 线程;Socket sockClient = null;private void btnConnect_Click(object sender, EventArgs e){IPAddress ip = IPAddress.Parse(txtIp.Text.Trim());IPEndPoint endPoint=new IPEndPoint (ip,int.Parse(txtPort.Text.Trim()));sockClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);try{ShowMsg("与服务器连接中……");sockClient.Connect(endPoint);}catch (SocketException se){MessageBox.Show(se.Message);return;//this.Close();}ShowMsg("与服务器连接成功!!!");threadClient = new Thread(RecMsg);threadClient.IsBackground = true;threadClient.Start();}void RecMsg(){while (true){// 定义一个2M的缓存区;byte[] arrMsgRec = new byte[1024 * 1024 * 2];// 将接受到的数据存入到输入  arrMsgRec中;int length = -1;try{length = sockClient.Receive(arrMsgRec); // 接收数据,并返回数据的长度;}catch (SocketException se){ShowMsg("异常;" + se.Message);return;}catch (Exception e){ShowMsg("异常:"+e.Message);return;}if (arrMsgRec[0] == 0) // 表示接收到的是消息数据;{string strMsg = System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length-1);// 将接受到的字节数据转化成字符串;ShowMsg(strMsg);}if (arrMsgRec[0] == 1) // 表示接收到的是文件数据;{try{SaveFileDialog sfd = new SaveFileDialog();if (sfd.ShowDialog(this) == System.Windows.Forms.DialogResult.OK){// 在上边的 sfd.ShowDialog() 的括号里边一定要加上 this 否则就不会弹出 另存为 的对话框,而弹出的是本类的其他窗口,,这个一定要注意!!!【解释:加了this的sfd.ShowDialog(this),“另存为”窗口的指针才能被SaveFileDialog的对象调用,若不加thisSaveFileDialog 的对象调用的是本类的其他窗口了,当然不弹出“另存为”窗口。】string fileSavePath = sfd.FileName;// 获得文件保存的路径;// 创建文件流,然后根据路径创建文件;using (FileStream fs = new FileStream(fileSavePath, FileMode.Create)){fs.Write(arrMsgRec, 1, length - 1);ShowMsg("文件保存成功:" + fileSavePath);}}}catch (Exception aaa){MessageBox.Show(aaa.Message);}}}}void ShowMsg(string str){txtMsg.AppendText(str + "\r\n");}// 发送消息;private void btnSendMsg_Click(object sender, EventArgs e){string strMsg = txtName.Text.Trim()+"\r\n"+"    -->"+ txtSendMsg.Text.Trim()+ "\r\n";byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);byte[] arrSendMsg = new byte[arrMsg.Length + 1];arrSendMsg[0] = 0; // 用来表示发送的是消息数据Buffer.BlockCopy(arrMsg, 0, arrSendMsg, 1, arrMsg.Length);sockClient.Send(arrSendMsg); // 发送消息;ShowMsg(strMsg);txtSendMsg.Clear();}// 选择要发送的文件;private void btnSelectFile_Click(object sender, EventArgs e){OpenFileDialog ofd = new OpenFileDialog();ofd.InitialDirectory = "D:\\";if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK){txtSelectFile.Text = ofd.FileName;}}//向服务器端发送文件private void btnSendFile_Click(object sender, EventArgs e){if (string.IsNullOrEmpty(txtSelectFile.Text)){MessageBox.Show("请选择要发送的文件!!!");}else{// 用文件流打开用户要发送的文件;using (FileStream fs = new FileStream(txtSelectFile.Text, FileMode.Open)){//在发送文件以前先给好友发送这个文件的名字+扩展名,方便后面的保存操作;string fileName = System.IO.Path.GetFileName(txtSelectFile.Text);string fileExtension = System.IO.Path.GetExtension(txtSelectFile.Text);string strMsg = "我给你发送的文件为: " + fileName + "\r\n";byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);byte[] arrSendMsg = new byte[arrMsg.Length + 1];arrSendMsg[0] = 0; // 用来表示发送的是消息数据Buffer.BlockCopy(arrMsg, 0, arrSendMsg, 1, arrMsg.Length);sockClient.Send(arrSendMsg); // 发送消息;byte[] arrFile = new byte[1024 * 1024 * 2];int length = fs.Read(arrFile, 0, arrFile.Length);  // 将文件中的数据读到arrFile数组中;byte[] arrFileSend = new byte[length + 1];arrFileSend[0] = 1; // 用来表示发送的是文件数据;Buffer.BlockCopy(arrFile, 0, arrFileSend, 1, length);// 还有一个 CopyTo的方法,但是在这里不适合; 当然还可以用for循环自己转化;sockClient.Send(arrFileSend);// 发送数据到服务端;txtSelectFile.Clear(); }}         }
}

}

C# TCP/IP客户端与服务端数据与文件的传输相关推荐

  1. 黑帽子Python——基础的网络编程工具——TCP的客户端和服务端

    学习自Python黑帽子(第二版) TCP的客户端和服务端 前言 TCP客户端 TCP服务端 问题 后记 前言 直接通过实践学习编程,很容易产生一些细节方面的知识错误,遇到不会的俺就问ChatGPT

  2. JAVA-建立TCP的客户端和服务端

    TCP客户端 客户端发数据到服务端 Tcp传输: 客户端建立的过程.思路:1.创建Tcp客户端socket服务.使用的是socket对象.建议该对象一创建就明确目的地.要连接的主机.2.如果连接建立成 ...

  3. 基于多线程的TCP局域网通信,客户端向服务端上传 文件简单实现源码

    客户端 import java.io.*; import java.net.Socket;/*** ### 作业3:* 完成文件上传案例学习* - 案例需求* 客户端:数据来自于本地文件,接收服务器反 ...

  4. C#在客户端和服务端操作Excel文件

    一.在客户端把数据导入到Excel文件步骤 1.创建Excel application对象,打开或生成Excel文件 //服务端创建StringBuilder对象     System.Text.St ...

  5. TCP通讯:客户端和服务端

    客户端: #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <stdio. ...

  6. [JAVA]递归实现客户端与服务端之间的文件与文件夹传输

    JAVA实现文件与文件夹传输 声明 其他方法 客户端: 服务端: 声明 本代码的文件夹传输并非完全由本人完成,本人只是在实现递归的基本思想上,稍微处理与改动了原作者的代码的结构,从而实现了文件与文件夹 ...

  7. 【学习笔记】在windows下进行基于TCP的本地客户端和服务端socket通信

    文章目录 socket介绍 java中使用socket 基于tcp的socket通信 使用ServerSocket类创建一个web服务器:(java) windows下的基于tcp的socket编程( ...

  8. php winform通信,C# Winform 通过Socket实现客户端和服务端TCP通信

    操作界面如下: 1.声明Socket 第一个参数:寻址方式,第二个参数:传输数据的方式,第三个参数:通信协议 Socket socket = new Socket(AddressFamily.Inte ...

  9. mysql服务器是否支持tcp/ip连接,(3)MySQL客户端与服务端的TCP/IP及socket连接方式-Go语言中文社区...

    MySQL客户端与服务端的TCP/IP及socket连接方式 客户端与服务器模型 客户端与服务端模型 TCP/IP方式连接 解释说明 TCP/IP套接字方式是MySQL在任何平台下都提供的连接方式,也 ...

最新文章

  1. Mansory算法分析
  2. git如何查看sshkey_Jenkins配置SSH Key下载代码
  3. 世界未解之谜之----------Android Gradle
  4. 数据库:SQLServer分页查询整理
  5. 17 操作系统第四章 磁盘管理 磁盘的结构 磁盘调度算法 减少磁盘延迟时间的方法
  6. 查询数据库前十条数据_入门数据分析的一些建议
  7. 基于静态类型分析的java程序函数调用图构建方法研究,JAVA的静态方法调用
  8. json解析和字符串解析_高效创建和解析定界字符串
  9. Entity Framework教程(第二版)
  10. 【转】使用C语言实现MD5消息摘要算法
  11. 《An Introduction to Ray Tracing》——2.2 Ray/Sphere Intersection And Mapping
  12. linux 命令行修改分辨率,Linux命令行(console)屏幕分辨率调整
  13. Entrez检索实例 - NCBI
  14. 如何给代码起个好名字
  15. 基于Open vSwitch搭建虚拟路由器
  16. 【报告分享】潮流涌动下的追潮众生与消费洞察-阿里妈妈.pdf(附下载链接)...
  17. Python第三方库turtle的应用
  18. Python:统计正负数个数
  19. ESP32串口通信 双机串口通信
  20. html获取问号后的参数,html问号后的值怎么获取

热门文章

  1. PHP的bc数学函数计算精度的坑
  2. 浏览器必备的管理工具,蓝色书签让你更方便
  3. JAVA毕业设计流浪狗领养系统计算机源码+lw文档+系统+调试部署+数据库
  4. 新生计算机能力水平测试,【新生必读】2018级新生计算机水平入学考试要点
  5. pattern类和matcher类,math类,Random类,Date类,SimpleDateFormat类,calender类
  6. mybatis配置mybatis.configuration.map-underscore-to-camel-case=true
  7. Leetcode95. 不同的二叉搜索树 II(C语言)
  8. Ubuntu系统修复
  9. java 输入一串字符统计大写字母个数小写字母个数及特殊符号并输出
  10. php+怎么处理图片白底,简单快速教您制作白底图