學習C#高階程式設計之Socket程式設計
阿新 • • 發佈:2019-01-05
一個簡單的伺服器端和客戶端程式
伺服器端
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; namespace _026_socket程式設計_TCP協議 { class Program { static void Main(string[] args) { //1.建立socket Socket tcpServer = new Socket (AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); //對應屬性分別是內網,流資料以及Tcp協議 //2.繫結ip和埠號 172.16.1.102 IPAddress ipaddress = new IPAddress(new byte[] {172,16,1,102});//獲取ip地址 EndPoint point = new IPEndPoint(ipaddress,7788);//IPEndPoint是對ip+埠做了一次封裝的類 tcpServer.Bind(point);//向作業系統申請一個可用的ip跟埠號 用來做通訊 //3.開始監聽(等待客戶端連線) tcpServer.Listen(100);//引數是最大連線數 Console.WriteLine("開始監聽"); Socket clientSocket = tcpServer.Accept();//暫停當前執行緒,直到有一個客戶端連線過來,之後進行下面的程式碼 //使用返回的socket跟客戶端做通訊 Console.WriteLine("一個客戶端連線過來了"); string message = "hello 歡迎你"; byte[] data = Encoding.UTF8.GetBytes(message);//對字串做編碼,得到一個字串的位元組陣列 clientSocket.Send(data); Console.WriteLine("向客戶端傳送了一條資料"); byte[] data2 = new byte[1024];//建立一個位元組陣列用來當做容器,去承接客戶端傳送過來的資料 int length = clientSocket.Receive(data2); string message2 = Encoding.UTF8.GetString(data2, 0, length);//把位元組資料轉換成一個字串 Console.WriteLine("接收到了一個從客戶端傳送來的訊息:" + message2); Console.ReadKey(); } } }
客戶端
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; namespace _001_socket程式設計_tcp協議_客戶端 { class Program { static void Main(string[] args) { //1.建立socket Socket tcpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //2.發起建立連線的請求 IPAddress ipaddress = IPAddress.Parse("172.16.1.102");//可以把一個字串的IP地址轉化成一個ipaddress的 //物件 EndPoint point = new IPEndPoint(ipaddress,7788); tcpClient.Connect(point);//通過ip:埠號 定位一個要連線到的伺服器端 byte[] data = new byte[1024]; int length = tcpClient.Receive(data);//這裡傳遞一個byte陣列,實際上這個data陣列用來接收資料 //length返回值表示接收了多少位元組的資料 string message = Encoding.UTF8.GetString(data,0,length);//只把接收到的資料做一個轉化 Console.WriteLine(message); //向伺服器端傳送訊息 string message2 = Console.ReadLine();//讀取使用者的輸入 把輸入傳送到伺服器端 tcpClient.Send(Encoding.UTF8.GetBytes(message2));//把字串轉化成位元組陣列,然後傳送到伺服器端 Console.ReadKey(); } } }
伺服器端結果
客戶端結果
聊天室_socket_tcp伺服器端
Client.cs用來和客戶端做通訊,處理客戶端來的訊息
using System; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace _027_聊天室_socket_tcp伺服器端 { //用來和客戶端做通訊 class Client { private Socket clientSocket; private Thread t; private byte[] data = new byte[1024];//資料容器 public Client(Socket s) { clientSocket = s; //啟動一個執行緒 處理客戶端的資料接收 Thread t = new Thread(ReceiveMessage); t.Start(); } private void ReceiveMessage() { //一直接收客戶端的資料 while (true) { //在接收資料之前 判斷一下socket連結是否斷開 if(clientSocket.Poll(10, SelectMode.SelectRead)) { clientSocket.Close(); break;//跳出迴圈 終止執行緒的執行 } int length = clientSocket.Receive(data); string message = Encoding.UTF8.GetString(data, 0, length); //接收到資料的時候, 要把這個資料分發到客戶端 //廣播這個訊息 Program.BroadcastMessage(message); Console.WriteLine("收到了訊息:" + message); } } public void SendMessage(string message) { byte[] data = Encoding.UTF8.GetBytes(message); clientSocket.Send(data); } public bool Connected { get { return clientSocket.Connected; } } } }
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace _027_聊天室_socket_tcp伺服器端
{
class Program
{
static List<Client> clientList = new List<Client>();
//廣播訊息
public static void BroadcastMessage(string message)
{
var notConnectedList = new List<Client>();
foreach (var client in clientList)
{
if(client.Connected)
client.SendMessage(message);
else
{
notConnectedList.Add(client);
}
}
foreach(var temp in notConnectedList)
{
clientList.Remove(temp);
}
}
static void Main(string[] args)
{
Socket tcpServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
ProtocolType.Tcp);
tcpServer.Bind(new IPEndPoint(IPAddress.Parse("192.168.184.1"), 7788));
tcpServer.Listen(100);
Console.WriteLine("Server running...");
while (true)
{
Socket clientSocket = tcpServer.Accept();
Console.WriteLine("a client is connected!");
Client client = new Client(clientSocket);//把與每個客戶端通訊的邏輯(收發訊息)
//放到client物件裡面進行處理
clientList.Add(client);
}
}
}
}
客戶端使用unity,介面如下:
核心程式碼:
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
public class ChatManager : MonoBehaviour {
public string ipaddress = "192.168.184.1";
public int port = 7788;
public UIInput textInput;
public UILabel chatLabel;
private Socket clientSocket;
private Thread t;
private byte[] data = new byte[1024];//資料容器
private string message = "";//訊息容器
// Use this for initialization
void Start () {
ConnectToServer();
}
// Update is called once per frame
void Update () {
if (message != null && message != "")
{
chatLabel.text += "\n" + message;
message = "";//清空訊息
}
}
void ConnectToServer()
{
clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//跟伺服器端建立連線
clientSocket.Connect(new IPEndPoint(IPAddress.Parse(ipaddress), port));
//建立一個新的執行緒 用來接收訊息
t = new Thread(ReceiveMessage);
t.Start();
}
//這個執行緒方法用來迴圈接收方法
void ReceiveMessage()
{
while (true)
{
if (clientSocket.Connected == false)
break;
int length = clientSocket.Receive(data);
message = Encoding.UTF8.GetString(data, 0, length);
//chatLabel.text += "\n" + message;
}
}
void SendMessage(string message)
{
byte[] data = Encoding.UTF8.GetBytes(message);
clientSocket.Send(data);
}
public void OnSendButtonClick()
{
string value = textInput.value;
SendMessage(value);
textInput.value = "";
}
void OnDestroy()
{
clientSocket.Shutdown(SocketShutdown.Both);//關閉:既不接受,也不傳送
clientSocket.Close();//關閉連結
}
}
結果展示如下:
UDP協議網路程式設計
伺服器端
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace _028_socket程式設計_UDP協議_伺服器端
{
class Program
{
static Socket udpServer;
static void Main(string[] args)
{
udpServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
udpServer.Bind(new IPEndPoint(IPAddress.Parse("172.16.1.102"), 7788));
new Thread(ReceiveMessage) {IsBackground = true }.Start();
//udpServer.Close();
Console.ReadKey();
}
static void ReceiveMessage()
{
//接收資料
while (true)
{
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
byte[] data = new byte[1024];
int length = udpServer.ReceiveFrom(data, ref remoteEndPoint);//這個方法會把資料的來源(ip:port)放到第二個引數上
string message = Encoding.UTF8.GetString(data, 0, length);
Console.WriteLine("從ip:" + (remoteEndPoint as IPEndPoint).Address.ToString() + ":" +
(remoteEndPoint as IPEndPoint).Port + "收到了資料:" + message);
}
}
}
}
客戶端
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace _002_socket程式設計_udp協議_客戶端
{
class Program
{
static void Main(string[] args)
{
//建立socket
Socket udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//傳送資料
while (true)
{
EndPoint serverPoint = new IPEndPoint(IPAddress.Parse("172.16.1.102"), 7788);
string message = Console.ReadLine();
byte[] data = Encoding.UTF8.GetBytes(message);
udpClient.SendTo(data, serverPoint);
}
Console.ReadKey();
}
}
}
TCP與UDP的區別:
1.基於連線與無連線;
2.對系統資源的要求(TCP較多,UDP少);
3.UDP程式結構較簡單;
4.流模式與資料報模式 ;
5.TCP保證資料正確性,UDP可能丟包,TCP保證資料順序,UDP不保證。
TcpListener和TcpClient:兩個封裝類
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace _029_tcplistener
{
class Program
{
static void Main(string[] args)
{
//1.TcpListener對socket進行了封裝,這個類裡面自己會去建立socket物件
TcpListener listener = new TcpListener(IPAddress.Parse("172.16.1.102"),7788);
//2.開始進行監聽
listener.Start();//開始進行監聽
//3.等待客戶端連線過來
TcpClient client = listener.AcceptTcpClient();
//4.取得客戶端傳送過來的資料
NetworkStream stream = client.GetStream();//得到了一個網路流 從這個網路流可以取得客戶端傳送過來的資料
while (true)
{
byte[] data = new byte[1024];//建立一個數據容器,用來承接資料
int length = stream.Read(data, 0, 1024);//讀取資料
//0表示從陣列的哪個索引開始存放資料
//1024表示最大讀取的位元組數
string message = Encoding.UTF8.GetString(data, 0, length);
Console.WriteLine("收到了訊息:" + message);
}
stream.Close();
client.Close();
listener.Stop();
Console.ReadKey();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace tcpclient
{
class Program
{
static void Main(string[] args)
{
//當我們建立tcpclient物件的時候,就會跟server去建立連線
TcpClient client = new TcpClient("172.16.1.102",7788);
NetworkStream stream = client.GetStream();
//read用來讀寫資料,write用來寫入資料就是傳送資料
while (true)
{
string message = Console.ReadLine();
byte[] data = Encoding.UTF8.GetBytes(message);
stream.Write(data, 0, data.Length);
}
stream.Close();
client.Close();
Console.ReadKey();
}
}
}
UdpClient
伺服器端
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace _030_UdpClient
{
class Program
{
static void Main(string[] args)
{
//建立udpclient 繫結ip跟埠號
UdpClient udpClient = new UdpClient(new IPEndPoint(IPAddress.Parse("172.16.1.102"),7788));
//接收資料
IPEndPoint point = new IPEndPoint(IPAddress.Any, 0);
while (true)
{
byte[] data = udpClient.Receive(ref point);//確定point確定資料來自哪個IP的哪個埠號,返回的是一個位元組陣列,就是我們的資料
string message = Encoding.UTF8.GetString(data);
Console.WriteLine("收到了訊息:" + message);
}
udpClient.Close();
Console.ReadKey();
}
}
}
客戶端
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace _004_udpclient
{
class Program
{
static void Main(string[] args)
{
//建立udpclient物件
UdpClient client = new UdpClient();
while (true)
{
string message = Console.ReadLine();
byte[] data = Encoding.UTF8.GetBytes(message);
client.Send(data, data.Length, new IPEndPoint(IPAddress.Parse("172.16.1.102"), 7788));
}
client.Close();
Console.ReadKey();
}
}
}
結果