.Net.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks; namespace SocketIM
{
////// Net : 提供静态方法,对常用的网络操作进行封装
public class Net
{
public class ObjectState
{
public string fileName { get; set; }
public Socket workSocket { get; set; }
public Thread workThread { get; set; }
}
private Net()
{
} ////// 向远程主机发送数据
//////要发送数据且已经连接到远程主机的 Socket///待发送的数据///发送数据的超时时间,以秒为单位,可以精确到微秒///0:发送数据成功;-1:超时;-2:发送数据出现错误;-3:发送数据时出现异常////// 当 outTime 指定为-1时,将一直等待直到有数据需要发送
public static int SendData(Socket socket, byte[] buffer, int outTime)
{
if (socket == null || socket.Connected == false)
{
throw new ArgumentException("参数socket 为null,或者未连接到远程计算机");
}
if (buffer == null || buffer.Length == )
{
throw new ArgumentException("参数buffer 为null ,或者长度为 0");
} int flag = ;
try
{
int totalLen = buffer.Length;
int sndLen = ; while (true)
{
if ((socket.Poll(outTime * , SelectMode.SelectWrite) == true))
{ // 收集了足够多的传出数据后开始发送
sndLen = socket.Send(buffer, sndLen, totalLen, SocketFlags.None);
totalLen -= sndLen;
if (totalLen == )
{ // 数据已经全部发送
flag = ;
break;
}
else
{
if (sndLen > )
{ // 数据部分已经被发送continue;
}
else
{ // 发送数据发生错误
flag = -;
break;
}
}
}
else
{ // 超时退出
flag = -;
break;
}
}
}
catch (SocketException e)
{ flag = -;
}
return flag;
} ////// 向远程主机发送文件
//////要发送数据且已经连接到远程主机的 socket///待发送的文件名称///文件发送时的缓冲区大小///发送缓冲区中的数据的超时时间///0:发送文件成功;-1:超时;-2:发送文件出现错误;-3:发送文件出现异常;-4:读取待发送文件发生错误////// 当 outTime 指定为-1时,将一直等待直到有数据需要发送
public static int SendFile(string ip, int port, string fileName, int maxBufferLength, int outTime)
{
IPAddress address = IPAddress.Parse(ip);
IPEndPoint endpoint = new IPEndPoint(address, port);
//创建服务端负责监听的套接字,参数(使用IPV4协议,使用流式连接,使用TCO协议传输数据)
Thread.Sleep();
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(endpoint);
if (socket.Connected)
{
Console.WriteLine(socket.RemoteEndPoint + "连接成功");
}
if (fileName == null || maxBufferLength <= )
{
throw new ArgumentException("待发送的文件名称为空或发送缓冲区的大小设置不正确.");
}
int flag = ;
try
{
FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
long fileLen = fs.Length; // 文件长度
long totalLen = fileLen; // 未读取部分
int readLen = ; // 已读取部分
byte[] buffer = null; if (fileLen <= maxBufferLength)
{ /* 文件可以一次读取*/
buffer = new byte[fileLen];
readLen = fs.Read(buffer, , (int)fileLen);
flag = SendData(socket, buffer, outTime);
}
else
{
/* 循环读取文件,并发送 */
while (totalLen != )
{
if (totalLen < maxBufferLength)
{
buffer = new byte[totalLen];
readLen = fs.Read(buffer, , Convert.ToInt32(totalLen));
}
else
{
buffer = new byte[maxBufferLength];
readLen = fs.Read(buffer, , maxBufferLength);
}
if ((flag = SendData(socket, buffer, outTime)) < )
{
break;
}
totalLen -= readLen;
}
}
fs.Flush();
fs.Close();
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
catch (IOException e)
{ flag = -;
}
if (flag == )
{
Console.WriteLine(fileName + "文件发送成功");
socket.Close();
Console.WriteLine("连接关闭");
}
else
{
Console.WriteLine(fileName + "文件发送失败,i=" + flag);
}
return flag;
}
private static void WatchConnecting(object info)
{
ObjectState state = (ObjectState)info;
Socket socketWatch = state.workSocket;
while (true)//持续不断的监听客户端的请求
{
//开始监听 客户端连接请求,注意:Accept方法,会阻断当前的线程
Socket connection = socketWatch.Accept(); if (connection.Connected)
{ //创建通信线程
Thread thradRecMsg = new Thread(RecMsg);
state.workSocket = connection;
state.workThread = thradRecMsg;
thradRecMsg.IsBackground = true;
thradRecMsg.Start(state); }
} }
////// 接收消息
private static void RecMsg(object socketClientPara)
{ ObjectState state = (ObjectState)socketClientPara;
string fileName = state.fileName;//$@"d:HQ.dat";//获得用户保存文件的路径
Socket socketClient = state.workSocket;
FileStream fs = null;
while (true)
{
//定义一个接受用的缓存区(100M字节数组)
//将接收到的数据存入arrMsgRec数组,并返回真正接受到的数据的长度
if (socketClient.Connected)
{
try
{
//因为终端每次发送文件的最大缓冲区是512字节,所以每次接收也是定义为512字节
byte[] buffer = new byte[];
int size = ;
//统计实际文件大小
long len = ;
//创建文件流,然后让文件流来根据路径创建一个文件
fs = new FileStream(fileName, FileMode.Append);
DateTime oTimeBegin = DateTime.Now;
//从终端不停的接受数据,然后写入文件里面,只到接受到的数据为0为止,则中断连接
while ((size = socketClient.Receive(buffer, , buffer.Length, SocketFlags.None)) > )
{
fs.Write(buffer, , size);
len += size;
}
DateTime oTimeEnd = DateTime.Now;
TimeSpan oTime = oTimeEnd.Subtract(oTimeBegin);
fs.Flush();
fs.Close(); socketClient.Shutdown(SocketShutdown.Both);
socketClient.Close();
Console.WriteLine("文件保存成功:" + fileName);
Console.WriteLine("接收文件用时:" + oTime.ToString() + ",文件大小:" + len / + "kb");
}
catch (Exception ex)
{
if (fs != null)
{
fs.Dispose();
}
if (File.Exists(fileName))
{
File.Delete(fileName);
}
Console.WriteLine(socketClient.RemoteEndPoint + "下线了"); break;
}
}
else
{ }
}
} public static void AcceptFile(string ip, int port, string fileName)
{
//创建服务端负责监听的套接字,参数(使用IPV4协议,使用流式连接,使用Tcp协议传输数据)
Socket socketListen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socketListen.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
//获取Ip地址对象
IPAddress address = IPAddress.Parse(ip);
//创建包含Ip和port的网络节点对象
IPEndPoint endpoint = new IPEndPoint(address, port); //将负责监听的套接字绑定到唯一的Ip和端口上
socketListen.Bind(endpoint);
//设置监听队列的长度
socketListen.Listen();
connectDone.Set();
ObjectState state = new ObjectState(); //创建负责监听的线程,并传入监听方法
Thread threadWatch = new Thread(WatchConnecting);
state.fileName = fileName;
state.workSocket = socketListen;
state.workThread = threadWatch;
threadWatch.IsBackground = true;//设置为后台线程
threadWatch.Start(state);//开始线程 }
public static void CloseTcpSocket(Thread threadWatch, Socket socketWatch)
{ threadWatch.Abort();
socketWatch.Close();
Console.WriteLine("服务器关闭监听");
}
public static ManualResetEvent connectDone = new ManualResetEvent(false);
public static void FileMove(string ip, int port, string fromPath, string toPath)
{ AcceptFile(ip, port, toPath);
connectDone.WaitOne();
int i = SendFile(ip, port, fromPath, , );
Console.WriteLine("文件从" + fromPath + "到" + toPath + "移动成功!!!!");
} }
}
.调用代码
private void button1_Click(object sender, EventArgs e)
{
//string topath = $@"d:HQ.dat";
//string frompath = $@"e:\HQ.dat";
//Net.FileMove("127.0.0.1", 11000, frompath,topath);
string topath = $@"d:bb\HQ.dat";
string frompath = $@"d:aa\HQ.dat";
Net.FileMove("127.0.0.1", , frompath, topath);
}