Socket发送或接收文件
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Socket发送或接收⽂件
最近学习了⼀下Socket ,下⾯是实现像《飞鸽》类似的功能,这⾥只提供了简单的使⽤规则和⼀些做时遇到地饿问题,算是备忘吧!!
---------------------------------------------------
----------使⽤UDP 发送数据报,到指定的⽹段---------
using ;
using .Sockets;
using System.Windows.Forms;
using System.IO;
/// <summary>
/// 启动所有线程
/// </summary>
private void StartThread()
{
//发送⽤户在线信息
Thread send = new Thread(new ThreadStart(this.SendUserInfo));
send.IsBackground = true;
send.Start();
//接收⽤户在线信息
Thread lsn = new Thread(new ThreadStart(this.StartListening));
lsn.IsBackground = true;
lsn.Start();
//侦听消息和⽂件的传输端⼝
Thread sendMsg = new Thread(new ThreadStart(this.m_sendMSG.ListeningMSG));
sendMsg.IsBackground = true;
sendMsg.SetApartmentState(ApartmentState.STA);
sendMsg.Start();
}
/// <summary>
/// 发送UDP 数据报到指定⽹段内各终端机的 4095 端⼝
/// (发送在线⽤户信息)
/// </summary>
public void SendUserInfo()
{
UdpClient udpClient = new UdpClient();
IPEndPoint ep = new IPEndPoint(IPAddress.Parse("192.168.1.255"), 4095);
string str = "user:" + .Dns.GetHostName()
+ ":" + .Dns.GetHostEntry(.Dns.GetHostName()).AddressList[0];
byte[] dgram = System.Text.Encoding.Default.GetBytes(str);
while (true)
{
udpClient.Send(dgram, dgram.Length, ep);
System.Threading.Thread.Sleep(2000); //使调⽤该⽅法的线程休眠2000毫秒
}
}
/// <summary>
/// 接收 4095 端⼝所有数据包
/// (监听线⽤户发送的在线确认信息)
/// </summary>
public void StartListening()
{
UdpClient udpClient = new UdpClient(4095);//udp 通讯的端⼝号
IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);
while (true)
{
byte[] dgram = udpClient.Receive(ref ep);
string str = System.Text.Encoding.Default.GetString(dgram);
string[] arr = str.Split(':');
if (arr == null || arr.Length < 3)
continue;
if (arr[0] != "user")
continue;
string houtName = arr[1];
string ip = arr[2];
if (!hs.Contains(ip))
{
hs.Add(ip, houtName);
}
··· ···
}
}
}
-------------------------------------------------------
-------------------通过 TCP 发送消息-------------------
1.通过指定的寻址⽅案,以字符流⽅式和Tcp通信,初始化套接字
socketSent = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
2. 设置服务器IP地址和端⼝
ipSent = new IPEndPoint(IPAddress.Parse(ip), 8001);
3. 与服务器进⾏连接
socketSent.Connect(ipSent);
4. 将要发送的消息转化为字节流,然后发送
socketSent.Send(Encoding.Default.GetBytes(msg));
----------------------------------------------------
通过 TCP 发送⽂件(最基本的设置)
⾸先要设置端⼝的监听,之后再发送数据包
1.命名空间:
using ;
using .Sockets;
using System.Windows.Forms;
using System.IO;
2.监听端⼝设置
//初始化接受套接字:寻址⽅案,以字符流⽅式和Tcp通信
Socket socketMsg = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //获取本机IP地址
IPAddress hostIP=Dns.GetHostEntry(Dns.GetHostName()).AddressList[0];
//
PEndPoint hostPoint=new IPEndPoint("本机IP地址",8000);
//设置服务器IP地址和端⼝
socketMsg.Bind(hostPoint);
//建⽴监听
socketMsg.Listen(1024);
while (true)
{
Socket newSocket = socketMsg.Accept();
//缓冲区
byte[] buffer = new byte[1024];
//接受数据流到缓冲区,len为接受到的字节数
int len = newSocket.Receive(buffer);
//创建写⽂件流
FileStream writer = new FileStream("c://test1.txt", FileMode.OpenOrCreate, FileAccess.Write);
byte[] buffer = new byte[1024];
len = newSocket.Receive(buffer)
string msg=Encoding.Default.GetString(buffer, 0, len );
if(msg!="开始传送的标志符")
continue;
while ((len = newSocket.Receive(buffer)) != 0)
{
msg = Encoding.Default.GetString(buffer, 0, len );
if (msg == "结束传送的标志符")
break;
writer.Write(buffer, 0, len );
}
writer.Close();
}
3.送⽂件
//初始化⽂件读写流
FileStream readSream = new FileStream("c://test2.txt", FileMode.Open, FileAccess.Read);
//初始化接受套接字:寻址⽅案,以字符流⽅式和Tcp通信
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("IP地址"), 8000);
//建⽴连接
socket.Connect(endPoint);
//1.发送:⽂件发送开始标记和⽂件名
socket.Send(Encoding.Default.GetBytes("开始传送的标志符"));
//2.发送⽂件
byte[] buffer = new byte[1024];
int n = 0;
while ((n = readSream.Read(buffer, 0, 1024)) != 0)
{
//调试时使⽤
//string str = Encoding.Default.GetString(buffer, 0, n);
//发送字节流
socket.Send(buffer,n,SocketFlags.None);
//socket.Send(buffer);
}
//3.发送:⽂件发送结束符
socket.Send(Encoding.Default.GetBytes("结束传送的标志符"));
socket.Close();
readSream.Close();
----------------------------------------------------
遇到的异常及解决⽅法:
1.在可以调⽤ OLE 之前,必须将当前线程设置为单线程单元(STA)模式。
请确保您的 Main 函数带有 STAThreadAttribute 标记。
只有将调试器附加到该进程才会引发此异常。
分析:因为使⽤线程,在线程中有调⽤了保存组件所以发⽣此异常
解决:将线程的模式设置为STA模式。
TreadName.SetApartmentState(ApartmentState.STA);
2.线程间操作⽆效: 从不是创建控件“lv”的线程访问它。
分析:因为在⾮本窗体的线程上,操作了本窗体的控件,所以引发了该异常。
解决:使⽤线程封送处理该问题,通过本窗体的 this.BeginInvoke() ⽅法,使其它线程可以操作窗体控件
/// <summary>
/// 修改本窗体控件(封送处理所需的⽅法,该代理要于线程的⽅法的参数列表匹配)
/// </summary>
private delegate void InvokeInitIpList(ListeningAgos ags);
/// <summary>
/// 线程调⽤的本窗体中的⽅法
/// </summary>
/// <param name="sa">包含所有在线⽤户信息</param>
void m_lsn_OnListening(ListeningAgos sa)
{
//在其它线程中通过安全的线程访问本窗体控件(其它线程访问本窗体控件,如不⽤该⽅法调⽤会发⽣异常) //事件封送处理
this.BeginInvoke(new InvokeInitIpList(InitIpList),new object[]{sa});
}。