C#完整的通信代码(点对点,点对多,同步,异步,UDP,TCP)

本文展示了C#实现的UDP服务器和客户端通信代码,包括点对点和点对多的通信场景。同时,还提供了TCP客户端和服务器的示例,以及FTP文件下载的代码片段。这些代码涵盖了同步和异步通信,适用于不同的网络通信需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C# code
namespace UDPServer
{
    class Program
    {
        static void Main(string[] args)
        {
            int recv;
            byte[] data = new byte[1024];

            //构建TCP 服务器

            //得到本机IP,设置TCP端口号        
            IPEndPoint ipep = new IPEndPoint(IPAddress.Any , 8001);
            Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram , ProtocolType.Udp);

            //绑定网络地址
            newsock.Bind(ipep);

            Console.WriteLine("This is a Server, host name is {0}",Dns.GetHostName());

            //等待客户机连接
            Console.WriteLine("Waiting for a client...");

            //得到客户机IP
            IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
            EndPoint Remote = (EndPoint)(sender);
            recv = newsock.ReceiveFrom(data, ref Remote);
            Console .WriteLine ("Message received from {0}: ", Remote.ToString ());
            Console .WriteLine (Encoding .ASCII .GetString (data ,0,recv ));

            //客户机连接成功后,发送欢迎信息
            string welcome = "Welcome ! ";

            //字符串与字节数组相互转换
            data  = Encoding .ASCII .GetBytes (welcome );

            //发送信息
            newsock .SendTo (data ,data.Length ,SocketFlags .None ,Remote );
            while (true )
            {
                data =new byte [1024];
                //发送接受信息
                recv =newsock.ReceiveFrom(data ,ref Remote);
                Console .WriteLine (Encoding .ASCII .GetString (data ,0,recv));
                newsock .SendTo (data ,recv ,SocketFlags .None ,Remote );
            }
        }

        }
    }


--------------------------------------------------------------------------------

C# code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace UDPClient
{
    class Program
    {
        static void Main(string[] args)
        {
            byte[] data = new byte[1024];
            string input ,stringData;

            //构建TCP 服务器

            Console.WriteLine("This is a Client, host name is {0}", Dns.GetHostName());

            //设置服务IP,设置TCP端口号
            IPEndPoint ipep = new IPEndPoint(IPAddress .Parse ("127.0.0.1") , 8001);

            //定义网络类型,数据连接类型和网络协议UDP
            Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

            string welcome = "Hello! ";
            data = Encoding.ASCII.GetBytes(welcome);
            server.SendTo(data, data.Length, SocketFlags.None, ipep);
            IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
            EndPoint Remote = (EndPoint)sender;

            data = new byte[1024];
            int recv = server.ReceiveFrom(data, ref Remote);
            Console.WriteLine("Message received from {0}: ", Remote.ToString());
            Console.WriteLine(Encoding .ASCII .GetString (data,0,recv));
            while (true)
            {
                input = Console .ReadLine ();
                if (input =="exit")
                    break ;
                server .SendTo (Encoding .ASCII .GetBytes (input ),Remote );
                data = new byte [1024];
                recv = server.ReceiveFrom(data, ref Remote);
                stringData = Encoding.ASCII.GetString(data, 0, recv);
                Console.WriteLine(stringData);
            }
            Console .WriteLine ("Stopping Client.");
            server .Close ();
        }

        }
    }

 

--------------------------------------------------------------------------------

C# code

//"开始"按钮事件

  private void button1_Click(object sender, System.EventArgs e) {

   //取得预保存的文件名

   string fileName=textBox3.Text.Trim();

   //远程主机

   string hostName=textBox1.Text.Trim();

   //端口

   int port=Int32.Parse(textBox2.Text.Trim());

   //得到主机信息

   IPHostEntry ipInfo=Dns.GetHostByName(hostName);

   //取得IPAddress[]

   IPAddress[] ipAddr=ipInfo.AddressList;

   //得到ip

   IPAddress ip=ipAddr[0];

   //组合出远程终结点

   IPEndPoint hostEP=new IPEndPoint(ip,port);

   //创建Socket 实例

   Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);

   try

   {

   //尝试连接

   socket.Connect(hostEP);

   }

   catch(Exception se)

   {

   MessageBox.Show("连接错误"+se.Message,"提示信息

   ,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);

  }

  //发送给远程主机的请求内容串

  string sendStr="GET / HTTP/1.1/r/nHost: " + hostName +

  "/r/nConnection: Close/r/n/r/n";

   //创建bytes字节数组以转换发送串

   byte[] bytesSendStr=new byte[1024];

   //将发送内容字符串转换成字节byte数组

   bytesSendStr=Encoding.ASCII.GetBytes(sendStr);

  try

  {

  //向主机发送请求

  socket.Send(bytesSendStr,bytesSendStr.Length,0);

  }

  catch(Exception ce)

   {

   MessageBox.Show("发送错误:"+ce.Message,"提示信息

   ,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);

   }

   //声明接收返回内容的字符串

   string recvStr="";

   //声明字节数组,一次接收数据的长度为1024字节

   byte[] recvBytes=new byte[1024];

   //返回实际接收内容的字节数

   int bytes=0;

  //循环读取,直到接收完所有数据

  while(true)

  {

  bytes=socket.Receive(recvBytes,recvBytes.Length,0);

  //读取完成后退出循环

  if(bytes〈=0)

  break;

  //将读取的字节数转换为字符串

  recvStr+=Encoding.ASCII.GetString(recvBytes,0,bytes);

  }

  //将所读取的字符串转换为字节数组

  byte[] content=Encoding.ASCII.GetBytes(recvStr);

   try

   {

   //创建文件流对象实例

   FileStream fs=new FileStream(fileName,FileMode.OpenOrCreate,FileAccess.ReadWrite);

  //写入文件

  fs.Write(content,0,content.Length);

  }

  catch(Exception fe)

   {

   MessageBox.Show("文件创建/写入错误:"+fe.Message,"提示信息",MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);

   }

   //禁用Socket

   socket.Shutdown(SocketShutdown.Both);

   //关闭Socket

   socket.Close();

   }

   }

 


--------------------------------------------------------------------------------

C# code

TCPClient
TCPClient 类提供了一种使用 TCP 协议连接到某个端点的简化方法。它还通过 NetworkStream 对象展现在连接过程中读取或写入的数据。请参见下面从 QuickStart 文档中摘录的日期/时间客户机示例。

使用 C# 编写
using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Text;
class Client
{
public static void Main(String[] args)
{
TCPClient tcpc = new TCPClient();
Byte[] read = new Byte[32];
if (args.Length != 1)
{
Console.WriteLine(“请在命令行中指定服务器名称”);
return;
}
String server = args[0];
// 验证服务器是否存在
if (DNS.GetHostByName(server) == null)
{
Console.WriteLine(“找不到服务器:” + 服务器);
return;
}
// 尝试连接到服务器
if (tcpc.Connect(server, 13) == -1)
{
Console.WriteLine(“无法连接到服务器:” + 服务器);
return;
}
// 获取流
Stream s = tcpc.GetStream();
// 读取流并将它转换为 ASCII 码形式
int bytes = s.Read(read, 0, read.Length);
String Time = Encoding.ASCII.GetString(read);
// 显示数据
Console.WriteLine(“已接收到的” + 字节 + “字节”);
Console.WriteLine(“当前日期和时间是:” + 时间);
tcpc.Close();
}
}

TCPListener
TCPListener 类便于在来自某个客户机的 TCP 连接的特定套接字上进行侦听的工作。请参见下面包括在 QuickStart 文档中的日期/时间服务器示例。

使用 C# 编写
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class Server
{
public static void Main()
{
DateTime now;
String strDateLine;
Encoding ASCII = Encoding.ASCII;
// 在端口 13 进行侦听
TCPListener tcpl = new TCPListener(13);
tcpl.Start();
Console.WriteLine(“正在等待客户进行连接”);
Console.WriteLine(“请按 Ctrl+c 退出...”);
while (true)
{
// 接收会阻塞,直到有人连接上
Socket s = tcpl.Accept();
// 获取当前的日期和时间并将它连接成一个字符串
now = DateTime.Now;
strDateLine = now.ToShortDateString() + " " +
now.ToLongTimeString();
// 将该字符串转换成一个字节数组并发送它
Byte[] byteDateLine =
ASCII.GetBytes(strDateLine.ToCharArray());
s.Send(byteDateLine, byteDateLine.Length, 0);
Console.WriteLine(“发送” + strDateLine);
}
}
}

 

--------------------------------------------------------------------------------

#region "Download: File transfer FROM ftp server"
  /// <summary>
  /// Copy a file from FTP server to local
  /// </summary>
  /// <param name="sourceFilename">Target filename, if required</param>
  /// <param name="localFilename">Full path of the local file</param>
  /// <returns></returns>
  /// <remarks>Target can be blank (use same filename), or just a filename
  /// (assumes current directory) or a full path and filename</remarks>
  public bool Download(string sourceFilename, string localFilename, bool PermitOverwrite)
  {
  //2. determine target file
  FileInfo fi = new FileInfo(localFilename);
  return this.Download(sourceFilename, fi, PermitOverwrite);
  }


  //Version taking an FtpFileInfo
  public bool Download(FtpFileInfo file, string localFilename, bool permitOverwrite)
  {
  return this.Download(file.FullName, localFilename, permitOverwrite);
  }

  //Another version taking FtpFileInfo and FileInfo
  public bool Download(FtpFileInfo file, FileInfo localFI, bool permitOverwrite)
  {
  return this.Download(file.FullName, localFI, permitOverwrite);
  }

  //Version taking string/FileInfo
  public bool Download(string sourceFilename, FileInfo targetFI, bool permitOverwrite)
  {
  //1. check target
  if (targetFI.Exists && !(permitOverwrite))
  {
  throw (new ApplicationException("Target file already exists"));
  }

  //2. check source
  string target;
  if (sourceFilename.Trim() == "")
  {
  throw (new ApplicationException("File not specified"));
  }
  else if (sourceFilename.Contains("/"))
  {
  //treat as a full path
  target = AdjustDir(sourceFilename);
  }
  else
  {
  //treat as filename only, use current directory
  target = CurrentDirectory + sourceFilename;
  }

  string URI = Hostname + target;

  //3. perform copy
  System.Net.FtpWebRequest ftp = GetRequest(URI);

  //Set request to download a file in binary mode
  ftp.Method = System.Net.WebRequestMethods.Ftp.DownloadFile;
  ftp.UseBinary = true;

  //open request and get response stream
  using (FtpWebResponse response = (FtpWebResponse)ftp.GetResponse())
  {
  using (Stream responseStream = response.GetResponseStream())
  {
  //loop to read & write to file
  using (FileStream fs = targetFI.OpenWrite())
  {
  try
  {
  byte[] buffer = new byte[2048];
  int read = 0;
  do
  {
  read = responseStream.Read(buffer, 0, buffer.Length);
  fs.Write(buffer, 0, read);
  } while (!(read == 0));
  responseStream.Close();
  fs.Flush();
  fs.Close();
  }
  catch (Exception)
  {
  //catch error and delete file only partially downloaded
  fs.Close();
  //delete target file as it’s incomplete
  targetFI.Delete();
  throw;
  }
  }

  responseStream.Close();
  }

  response.Close();
  }

  return true;
  }
  #endregion


--------------------------------------------------------------------------------

简单的UDP收发.


发送

C# code

                    try
                    {
                        Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);  //向此网段发广播包
                          int UDPListenerPort = 8082;
                        IPAddress broadcast = IPAddress.Parse("192.168.0.255"); //此处根据IP及子网掩码改为相应的广播IP
                        string ts = "This is UPD string for sending";
                        byte[] sendbuf = Encoding.ASCII.GetBytes(ts);
                        IPEndPoint ep = new IPEndPoint(broadcast, UDPListenerPort);
                        s.SendTo(sendbuf, ep);

                    }
                    catch (Exception e)
                    {}


接收

C# code

           UdpClient listener;
            int UDPListenerPort = 8082;
            IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, UDPListenerPort);

            try
            {
                while (true)
                {
                    byte[] bytes = listener.Receive(ref groupEP);
                    string RecIP = groupEP.ToString().Substring(0, groupEP.ToString().IndexOf(":"));  //收到发送UPD端的IP
                    string RecStr = Encoding.ASCII.GetString(bytes, 0, bytes.Length);   //收到的UPD字符串
                }
            }
            catch
            {}

 

--------------------------------------------------------------------------------

C# code
TCPClient
TCPClient 类提供了一种使用 TCP 协议连接到某个端点的简化方法。它还通过 NetworkStream 对象展现在连接过程中读取或写入的数据。请参见下面从 QuickStart 文档中摘录的日期/时间客户机示例。


使用 C# 编写
using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Text;
class Client
{
public static void Main(String[] args)
{
TCPClient tcpc = new T…
[/Quote]


--------------------------------------------------------------------------------

来一个Remoting的:


C# code

using System;

namespace Remotable
{

    public class RemotableType : MarshalByRefObject
    {
        private string _internalString = "This is the RemotableType.";
        public string StringMethod()
        {
            return _internalString;
        }
    }

}

using System;
using System.Runtime.Remoting;

namespace RemotingFirst
{

    public class Listener
    {
        public static void Main()
        {
            RemotingConfiguration.Configure("Listener.exe.config");
            Console.WriteLine("Listening for requests. Press Enter to exit");
            Console.ReadLine();
        }
    }

}

using System;
using System.Runtime.Remoting;

namespace Client
{

    public class Client
    {

        public static void Main()
        {
            RemotingConfiguration.Configure("Client.exe.config");
            Remotable.RemotableType remoteObject = new Remotable.RemotableType();
            Console.WriteLine(remoteObject.StringMethod());
        }
    }

}

Listener.exe.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.runtime.remoting>
      <application>
         <service>
            <wellknown
               mode="Singleton"
               type="Remotable.RemotableType, RemotableType"
               objectUri="RemotableType.rem"
            />
         </service>
         <channels>
            <channel ref="http" port="8989"/>
         </channels>
      </application>
    </system.runtime.remoting>
</configuration>

 

 

--------------------------------------------------------------------------------

实只要用到Socket联接,基本上就得使用Thread,是交叉使用的。
C#封装的Socket用法基本上不算很复杂,只是不知道托管之后的Socket有没有其他性能或者安全上的问题。
在C#里面能找到的最底层的操作也就是socket了,概念不做解释。
程序模型如下:
WinForm程序 : 启动端口侦听;监视Socket联接情况;定期关闭不活动的联接;
Listener:处理Socket的Accept函数,侦听新链接,建立新Thread来处理这些联接(Connection)。
Connection:处理具体的每一个联接的会话。


1:WinForm如何启动一个新的线程来启动Listener:
  //start the server
  private void btn_startServer_Click(object sender, EventArgs e)
  {
  //this.btn_startServer.Enabled = false;
  Thread _createServer = new Thread(new ThreadStart(WaitForConnect));
  _createServer.Start();
  }
  //wait all connections
  private void WaitForConnect()
  {
  SocketListener listener = new SocketListener(Convert.ToInt32(this.txt_port.Text));
  listener.StartListening();
  }
因为侦听联接是一个循环等待的函数,所以不可能在WinForm的线程里面直接执行,不然Winform也就是无法继续任何操作了,所以才指定一个新的线程来执行这个函数,启动侦听循环。
这一个新的线程是比较简单的,基本上没有启动的参数,直接指定处理函数就可以了。
2:Listener如何启动循环侦听,并且启动新的带有参数的线程来处理Socket联接会话。
先看如何建立侦听:(StartListening函数)
IPEndPoint localEndPoint = new IPEndPoint(_ipAddress, _port);
  // Create a TCP/IP socket.
  Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  // Bind the socket to the local endpoint and listen for incoming connections.
  try
  {
  listener.Bind(localEndPoint);
  listener.Listen(20);//20 trucks

  // Start listening for connections.
  while (true)
  {
  // here will be suspended while waiting for a new connection.
  Socket connection = listener.Accept();
  Logger.Log("Connect", connection.RemoteEndPoint.ToString());//log it, new connection
  ……
  }
  }……
基本步骤比较简单:
建立本机的IPEndPoint对象,表示以本机为服务器,在指定端口侦听;
然后绑定到一个侦听Socket上;
进入while循环,等待新的联接;
如果有新的联接,那么建立新的socket来对应这个联接的会话。
  值得注意的就是这一句联接代码:listener.Accept()。执行这一句的时候,程序就在这个地方等待,直到有新的联检请求的时候程序才会执行下一句。这是同步执行,当然也可以异步执行。
 
  新的联接Socket建立了(Accept之后),对于这些新的socket该怎么办呢?他们依然是一个循环等待,所以依然需要建立新的Thread给这些Socket去处理会话(接收/发送消息),而这个Thread就要接收参数了。
  Thread本身是不能接收参数的,为了让它可以接收参数,可以采用定义新类,添加参数作为属性的方法来解决。
  因为每一个Socket是一个Connection周期,所以我定义了这么一个类public class Connection。这个类至少有这样一个构造函数public Connection(Socket socket); 之所以这么做,就是为了把Socket参

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值