程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#之Socket操作類實例解析

C#之Socket操作類實例解析

編輯:C#入門知識

C#之Socket操作類實例解析。本站提示廣大學習愛好者:(C#之Socket操作類實例解析)文章只能為提供參考,不一定能成為您想要的結果。以下是C#之Socket操作類實例解析正文


本文展現了一個C#的Socket操作類的完全實例,並附帶了用法解釋,分享給年夜家供年夜家參考之用。詳細辦法以下:

重要功效代碼以下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Collections;
using System.Net;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Collections.Specialized;
using System.Threading;
public class DuxSocketClient
{
 #region 公有字段
 /// <summary>
 /// 設置數據緩沖區年夜小 默許1024
 /// </summary>
 private static int m_maxpacket = 1024 * 4;
 public delegate void SendFileProgress(int progress);
 public delegate void ReceiveFileProgress(int progress);
 #endregion
 #region 辦事器偵聽
 /// <summary>
 /// 辦事器偵聽辦法 前往null則解釋沒有鏈接上
 /// </summary>
 /// <returns>前往一個套接字(Socket)</returns>
 public static Socket ListenerSocket(TcpListener listener)
 {
  try
  {
   Socket socket = listener.AcceptSocket();
   return socket;
  }
  catch
  {
   return null;
  }
 }
 /// <summary>
 /// 辦事器偵聽辦法 前往null則解釋沒有鏈接上
 /// </summary>
 /// <param name="listener"></param>
 /// <returns>前往一個收集流</returns>
 public static NetworkStream ListenerStream(TcpListener listener)
 {
  try
  {
   TcpClient client = listener.AcceptTcpClient();
   return client.GetStream();
  }
  catch
  {
   return null;
  }
 }
 #endregion
 #region 客戶端銜接
 public static Socket ConnectSocket(TcpClient tcpclient, IPEndPoint ipendpoint)
 {
  try
  {
   tcpclient.Connect(ipendpoint);
   return tcpclient.Client;
  }
  catch
  {
   return null;
  }
 }
 public static Socket ConnectSocket(TcpClient tcpclient, IPAddress ipadd, int port)
 {
  try
  {
   tcpclient.Connect(ipadd, port);
   return tcpclient.Client;
  }
  catch
  {
   return null;
  }
 }
 public static NetworkStream ConnectStream(TcpClient tcpclient, IPEndPoint ipendpoint)
 {
  try
  {
   tcpclient.Connect(ipendpoint);
   return tcpclient.GetStream();
  }
  catch
  {
   return null;
  }
 }
 public static NetworkStream ConnectStream(TcpClient tcpclient, IPAddress ipadd, int port)
 {
  try
  {
   tcpclient.Connect(ipadd, port);
   return tcpclient.GetStream();
  }
  catch
  {
   return null;
  }
 }
 #endregion
 #region Socket吸收數據
 /// <summary>
 /// 接收固定長度字符串
 /// </summary>
 /// <param name="socket"></param>
 /// <param name="size"></param>
 /// <returns></returns>
 public static byte[] ReceiveFixData(Socket socket, int size)
 {
  int offset = 0;
  int recv = 0;
  int dataleft = size;
  byte[] msg = new byte[size];
  while (dataleft > 0)
  {
   recv = socket.Receive(msg, offset, dataleft, 0);
   if (recv == 0)
   {
    break;
   }
   offset += recv;
   dataleft -= recv;
  }
  return msg;
 }
 /// <summary>
 /// 吸收變長字符串
 /// 為了處置粘包成績 ,每次發送數據時 包頭(數據字節長度) + 注釋
 /// 這個發送小數據
 /// 設置包頭的字節為8,不克不及跨越8位數的字節數組
 /// </summary>
 /// <param name="socket"></param>
 /// <returns>byte[]數組</returns>
 public static byte[] ReceiveVarData(Socket socket)
 {
  //每次接收數據時,吸收固定長度的包頭,包頭長度為8
  byte[] lengthbyte = ReceiveFixData(socket, 8);
  //length獲得字符長度 然後加工處置獲得數字
  int length = GetPacketLength(lengthbyte);
  //獲得注釋
  return ReceiveFixData(socket, length);  
 }
 /// <summary>
 /// 吸收T類對象,反序列化
 /// </summary>
 /// <typeparam name="T">吸收T類對象,T類必需是一個可序列化類</typeparam>
 /// <param name="socket"></param>
 /// <returns></returns>
 public static T ReceiveVarData<T>(Socket socket)
 {
  //先吸收包頭長度 固定8個字節
  byte[] lengthbyte = ReceiveFixData(socket, 8);
  //獲得字節長度
  int length = GetPacketLength(lengthbyte);
  byte[] bytecoll = new byte[m_maxpacket];
  IFormatter format = new BinaryFormatter();
  MemoryStream stream = new MemoryStream();
  int offset = 0; //吸收字節個數
  int lastdata = length; //還剩下若干沒有吸收,初始年夜小等於現實年夜小
  int receivedata = m_maxpacket; //每次吸收年夜小
  //輪回吸收
  int mark = 0; //標志幾回吸收到的數據為0長度
  while (true)
  {
   //剩下的字節數能否小於緩存年夜小
   if (lastdata < m_maxpacket) 
   {
    receivedata = lastdata; //就只吸收剩下的字節數
   }
   int count = socket.Receive(bytecoll,0,receivedata,0);
   if (count > 0)
   {
    stream.Write(bytecoll, 0, count);
    offset += count;
    lastdata -= count;
    mark = 0;
   }
   else
   {
    mark++;
    if (mark == 10)
    {
     break;
    }
   }
   if (offset == length)
   {
    break;
   }
  }
  stream.Seek(0, SeekOrigin.Begin); //必需要這個 或許stream.Position = 0;
  T t = (T)format.Deserialize(stream);
  stream.Close();
  return t;
 }
 /// <summary>
 /// 在事後獲得文件的文件名和年夜小
 /// 挪用此辦法吸收文件
 /// </summary>
 /// <param name="socket"></param>
 /// <param name="path">途徑必需存在</param>
 public static bool ReceiveFile(Socket socket, string path, string filename, long size,ReceiveFileProgress progress)
 {
  bool ret = false;
  if (Directory.Exists(path))
  {
   //重要是避免有重名文件
   string savepath = GetPath(path, filename); //獲得文件途徑
   //緩沖區
   byte[] file = new byte[m_maxpacket];
   int count = 0; //每次吸收的現實長度
   int receivedata = m_maxpacket; //每主要吸收的長度
   long offset = 0; //輪回吸收的總長度
   long lastdata = size; //殘剩若干還沒吸收
   int mark = 0;
   using (FileStream fs = new FileStream(savepath, FileMode.OpenOrCreate, FileAccess.Write))
   {
    if (size > 0)
    {
     while (true)
     {
      if (lastdata < receivedata)
      {
       receivedata = Convert.ToInt32(lastdata);
      }
      count = socket.Receive(file, 0, receivedata, SocketFlags.None);
      if (count > 0)
      {
       fs.Write(file, 0, count);
       offset += count;
       lastdata -= count;
       mark = 0;
      }
      else
      {
       mark++; //持續5次吸收為0字節 則跳出輪回
       if (mark ==10)
       {
        break;
       }
      }
      //吸收進度
      if (progress != null)
      {
       progress(Convert.ToInt32(((Convert.ToDouble(offset) / Convert.ToDouble(size)) * 100)));
      }
      //吸收終了
      if (offset == size)
      {
       ret = true;
       break;
      }
     }
    }
    fs.Close();
   }
  }
  return ret;
 }
 public static bool ReceiveFile(Socket socket, string path, string filename, long size)
 {
  return ReceiveFile(socket, path, filename, size,null);
 }
 /// <summary>
 /// 事後不曉得文件名和文件年夜小 用此辦法吸收
 /// 此辦法關於的發送辦法是SendFile()
 /// </summary>
 /// <param name="socket"></param>
 /// <param name="path">要保留的目次</param>
 public static void ReceiveFile(Socket socket, string path)
 {
  //獲得包頭信息字節數組 (文件名 + 文件年夜小 的字符串長度)
  //取前8位
  byte[] info_bt = ReceiveFixData(socket, 8);
  //獲得包頭信息字符長度
  int info_length = GetPacketLength(info_bt);
  //提取包頭信息,(文件名 + 文件年夜小 的字符串長度)
  byte[] info = ReceiveFixData(socket, info_length);
  //獲得文件信息字符串 (文件名 + 文件年夜小)
  string info_str = System.Text.Encoding.UTF8.GetString(info);
  string[] strs = info_str.Split('|');
  string filename = strs[0]; //文件名
  long length = Convert.ToInt64(strs[1]); //文件年夜小
  //開端吸收文件
  ReceiveFile(socket, path, filename, length);
 }
 private static int GetPacketLength(byte[] length)
 {
  string str = System.Text.Encoding.UTF8.GetString(length);
  str = str.TrimEnd('*'); ;//("*", "");
  int _length = 0;
  if (int.TryParse(str, out _length))
  {
   return _length;
  }
  else
  {
   return 0;
  }
 }
 /// <summary>
 /// 獲得文件途徑(避免有文件名反復)
 /// 如:aaa.txt曾經在directory目次下存在,則會獲得文件aaa(1).txt
 /// </summary>
 /// <param name="directory">目次名</param>
 /// <param name="file">文件名</param>
 /// <returns>文件途徑</returns>
 static int i = 0;
 static string markPath = String.Empty;
 public static string GetPath(string directory, string file)
 {
  if (markPath == String.Empty)
  {
   markPath = Path.Combine(directory, file);
  }
  string path = Path.Combine(directory, file);
  if (File.Exists(path))
  {
   i++;
   string filename = Path.GetFileNameWithoutExtension(markPath) + "(" + i.ToString() + ")";
   string extension = Path.GetExtension(markPath);
   return GetPath(directory, filename + extension);
  }
  else
  {
   i = 0;
   markPath = String.Empty;
   return path;
  }
 }
 #endregion
 #region Socket發送數據
 /// <summary>
 /// 發送固定長度新聞
 /// 發送字節數不克不及年夜於int型最年夜值
 /// </summary>
 /// <param name="socket"></param>
 /// <param name="msg"></param>
 /// <returns>前往發送字節個數</returns>
 public static int SendFixData(Socket socket, byte[] msg)
 {
  int size = msg.Length; //要發送字節長度
  int offset = 0;     //曾經發送長度
  int dataleft = size;  //剩下字符
  int senddata = m_maxpacket; //每次發送年夜小
  while (true)
  {
   //如多余下的字節數 小於 每次發送字節數
   if (dataleft < senddata)
   {
    senddata = dataleft;
   }
   int count = socket.Send(msg, offset, senddata, SocketFlags.None);
   offset += count;
   dataleft -= count;
   if (offset == size)
   {
    break;
   }
  }
  return offset;
 }
 /// <summary>
 /// 發送變長信息 格局 包頭(包頭占8位) + 注釋
 /// </summary>
 /// <param name="socket"></param>
 /// <param name="contact">發送文本</param>
 /// <returns></returns>
 public static int SendVarData(Socket socket, string contact)
 {
  //獲得字符長度
  int size = System.Text.Encoding.UTF8.GetBytes(contact).Length;
  //包頭字符
  string length = GetSendPacketLengthStr(size);
  //包頭 + 注釋
  byte[] sendbyte = System.Text.Encoding.UTF8.GetBytes(length + contact);
  //發送
  return SendFixData(socket, sendbyte);
 }
 /// <summary>
 /// 發送釀成信息
 /// </summary>
 /// <param name="socket"></param>
 /// <param name="bytes"></param>
 /// <returns></returns>
 public static int SendVarData(Socket socket, byte[] bytes)
 {
  //獲得包頭字節
  int size = bytes.Length;
  string length = GetSendPacketLengthStr(size);
  byte[] lengthbyte = System.Text.Encoding.UTF8.GetBytes(length);
  //發送包頭
  SendFixData(socket, lengthbyte);  //由於不曉得注釋是甚麼編碼所以沒有歸並
  //發送注釋
  return SendFixData(socket, bytes);
 }
 /// <summary>
 /// 發送T類型對象,序列化
 /// </summary>
 /// <typeparam name="T">T類型</typeparam>
 /// <param name="socket"></param>
 /// <param name="obj">T類型對象,必需是可序列化的</param>
 /// <returns></returns>
 public static int SendSerializeObject<T>(Socket socket, T obj)
 {
  byte[] bytes = SerializeObject(obj);
  return SendVarData(socket, bytes);
 }
 /// <summary>
 /// 發送文件
 /// </summary>
 /// <param name="socket">socket對象</param>
 /// <param name="path">文件途徑</param>
 /// <param name="issend">能否發送文件(頭)信息,假如以後曉得文件[年夜小,稱號]則為false</param>
 /// <param name="progress"></param>
 /// <returns></returns>
 public static bool SendFile(Socket socket, string path,bool issend,SendFileProgress progress)
 {
  bool ret = false;
  if (File.Exists(path))
  {
   FileInfo fileinfo = new FileInfo(path);
   string filename = fileinfo.Name;
   long length = fileinfo.Length;
   //發送文件信息
   if (issend)
   {
    SendVarData(socket, filename + "|" + length);
   }
   //發送文件
   long offset = 0;
   byte[] b = new byte[m_maxpacket];
   int mark = 0;
   using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
   {
    int senddata = b.Length;
    long i = length;
    //輪回讀取發送
    while (true)
    {
     int count = fs.Read(b, 0, senddata);
     if (count > 0)
     {
      socket.Send(b, 0, count, SocketFlags.None);
      offset += count;
      mark = 0;
     }
     else
     {
      mark++;
      if (mark == 10)
      {
       break;
      }
     }
     if (progress != null)
     {
      progress(Convert.ToInt32(((Convert.ToDouble(offset) / Convert.ToDouble(length)) * 100)));
     }
     if (offset == length)
     {
      break;
     }
     Thread.Sleep(50); //設置期待時光,以避免粘包
    }
   }
  }
  return ret;
 }
 /// <summary>
 /// 發送文件,不須要進度信息
 /// </summary>
 /// <param name="socket">socket對象</param>
 /// <param name="path">文件途徑</param>
 /// <param name="issend">能否產生(頭)信息</param>
 /// <returns></returns>
 public static bool SendFile(Socket socket, string path,bool issend)
 {
  return SendFile(socket, path, issend, null);
 }
 /// <summary>
 /// 發送文件,不須要進度信息和(頭)信息
 /// </summary>
 /// <param name="socket">socket對象</param>
 /// <param name="path">文件途徑</param>
 /// <returns></returns>
 public static bool SendFile(Socket socket, string path)
 {
  return SendFile(socket, path, false, null);
 }
 private static byte[] SerializeObject(object obj)
 {
  IFormatter format = new BinaryFormatter();
  MemoryStream stream = new MemoryStream();
  format.Serialize(stream, obj);
  byte[] ret = stream.ToArray();
  stream.Close();
  return ret;
 }
 private static string GetSendPacketLengthStr(int size)
 {
  string length = size.ToString() + "********"; //獲得size的長度
  return length.Substring(0, 8); //截取前前8位
 }
 #endregion
 #region NetworkStream吸收數據
 //沒寫
 #endregion
 #region NetworkStream發送數據
 //沒寫
 #endregion
}

用法解釋:

每一個吸收的辦法都對應著有發送辦法

如:

發送辦法:

SendFixData(socket,"01");

吸收辦法:

ReceiveFixData(socket,2); //size 就為2

不曉得發送文本長度:

string txt = ????  //不曉得有若干字符

發送辦法:

SendVarData(socket,txt); //有重載版

吸收辦法:

ReceiveVarData(socket);

願望本文所述實例對年夜家C#法式設計有所贊助。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved