總結:
服務器端先創建一個socketwatch監控等待客戶端連接,客戶端連接后循環socketwatch.accept()創建多個通信線程,每個通信線程再創建新的數據處理線程,數據必須循環接收
客戶端沒有socketwatch,直接創建socket,連接用connect(),發送用socket.send(),接收用receive(),數據也是循環接收的





一、服務器端單線程流程:
//服務器創建一個socket用於監聽
Socket socketwatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//設置ip和端口
IPAddress ip = IPAddress.Any;
IPEndPoint endpoint = new IPEndPoint(ip, Convert.ToInt32(textBox2.Text));
//綁定,即監聽
socketwatch.Bind(endpoint);
//設置監聽數量
socketwatch.Listen(10);
Msger("監聽成功!"+"\n\r");
//等待客戶端連接,並創建一個負責通信的socket, 單線程的話會一直等待accept(),卡死
Socket socketsend = socketwatch.Accept();
//接收遠程連接的ip信息
Msger(socketsend.RemoteEndPoint.ToString()+" 連接進來");
服務器端多線程: 一個監聽socket可以創建多個通信socket,監聽socket循環創建多個通信socket線程,其中每個通信socket再創建一個線程處理信息,預防卡死

private void button1_Click(object sender, EventArgs e)
{
//服務器創建一個socket用於監聽
Socket socketwatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//設置ip和端口
IPAddress ip = IPAddress.Any;
IPEndPoint endpoint = new IPEndPoint(ip, Convert.ToInt32(textBox2.Text));
//綁定,即監聽
socketwatch.Bind(endpoint);
//設置監聽數量
socketwatch.Listen(10);
Msger("監聽成功!" + "\n\r");
//創建線程預防卡死
Thread th = new Thread(Listen);
th.IsBackground = true;
th.Start(socketwatch);// 傳入監聽進程
}
//監聽socket循環創建多個通信socket線程,其中每個通信socket再創建一個線程處理信息,預防卡死
private void Listen(object s)
{
//類型轉換,as轉換成功返回值否則NULL
Socket socketwatch = s as Socket;
//等待客戶端連接,並創建一個負責通信的socket
while (true)
{
Socket socketsend = socketwatch.Accept();
Msger(socketsend.RemoteEndPoint.ToString() + " 連接進來" + "\t\r\n");
//創建一個新的線程處理客戶端發送過來的信息,否則一個socket就堵塞
Thread th = new Thread(Operater);
th.IsBackground = true;
th.Start(socketsend);
}
}
/// <summary>
/// 信息處理線程
/// </summary>
/// <param name="s">socket返回客戶端信息</param>
public void Operater(object s)
{
Socket socketsend = s as Socket;
//必須循環接收消息
while (true)
{
//創建字節數組並接受傳過來的數據,返回int為實際使用值
byte[] receive = new byte[1024 * 1024 * 2];
int realr = socketsend.Receive(receive);
//判斷客戶端發送的內容,如果為0則停止循環
if (realr == 0)
{
break;
}
//解碼
string text = Encoding.UTF8.GetString(receive, 0, realr);
//寫入textbox
Msger(text);
}
}
public void Msger(string ms)
{
textBox3.AppendText(ms + "\n\r"); //追加方式
}
二、客戶端簡單流程:
private void button4_Click(object sender, EventArgs e)
{
//創建socket
socketcustomsend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//設置ip和port
IPAddress ip = IPAddress.Parse(textBox5.Text);
IPEndPoint ipendpoint = new IPEndPoint(ip, Convert.ToInt32(textBox6.Text));
//連接
socketcustomsend.Connect(ipendpoint);
textBox4.Text = "連接成功!";
//創建進程接受服務器傳來的信息
Thread th = new Thread(CustomReceive);
th.IsBackground = true;
th.Start(socketcustomsend);
}
/// <summary>
/// 循環接受服務器傳來的信息
/// </summary>
/// <param name="s">通信的socket</param>
public void CustomReceive(object s)
{
while (true) //循環接收信息
{
Socket socketcustomsend = s as Socket;
byte[] b = new byte[1024 * 1024 * 5];
int r = socketcustomsend.Receive(b);
if (r==0) //0表示服務器端關閉
{
break;
}
textBox4.Text = Encoding.UTF8.GetString(b, 0, r);
}
}
三、通信的例子

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace socket通信
{
public partial class socket練習 : Form
{
public socket練習()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}
private void label1_Click(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
//服務器創建一個socket用於監聽
Socket socketwatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//設置ip和端口
IPAddress ip = IPAddress.Any;
IPEndPoint endpoint = new IPEndPoint(ip, Convert.ToInt32(textBox2.Text));
//綁定,即監聽
socketwatch.Bind(endpoint);
//設置監聽數量
socketwatch.Listen(10);
Msger("監聽成功!" + "\n\r");
//創建線程預防卡死
Thread th = new Thread(Listen);
th.IsBackground = true;
th.Start(socketwatch);// 傳入監聽進程
}
//監聽socket循環創建多個通信socket線程,其中每個通信socket再創建一個線程處理信息,預防卡死
// 全局服務器端通信socket
Socket socketsend;
Dictionary<string, Socket> sdic = new Dictionary<string, Socket>();
private void Listen(object s)
{
//類型轉換,as轉換成功返回值否則NULL
Socket socketwatch = s as Socket;
//等待客戶端連接,並創建一個負責通信的socket
while (true)
{
socketsend = socketwatch.Accept();
//將socket與ip信息放入字典集合
sdic.Add(socketsend.RemoteEndPoint.ToString(), socketsend);
//加入combox列表
comboBox1.Items.Add(socketsend.RemoteEndPoint.ToString());
//讓combox顯示當前連接的socket
comboBox1.SelectedItem= socketsend.RemoteEndPoint.ToString();
Msger(socketsend.RemoteEndPoint.ToString() + " 連接進來了" + "\t\r\n");
//創建一個新的線程處理客戶端發送過來的信息,否則一個socket就堵塞
Thread th = new Thread(Operater);
th.IsBackground = true;
th.Start(socketsend);
}
}
/// <summary>
/// 信息處理線程
/// </summary>
/// <param name="s">socket返回客戶端信息</param>
public void Operater(object s)
{
Socket socketsend = s as Socket;
//必須循環接收消息
while (true)
{
//創建字節數組並接受傳過來的數據,返回int為實際使用值
byte[] receive = new byte[1024 * 1024 * 10];
int realr = socketsend.Receive(receive);
//判斷客戶端發送的內容,如果為0則停止循環
if (realr == 0)
{
break;
}
//用文件頭判斷傳過來的是文字信息或文件的各種類型,0-文字信息 1-文件
if (receive[0]==0)
{
//解碼
string text = Encoding.UTF8.GetString(receive, 1, realr-1);
//寫入textbox
Msger(text);
}
else if(receive[0]==1) //文件則保存
{
SaveFileDialog sf = new SaveFileDialog();
sf.Filter = "所有文件|*.*";
sf.ShowDialog(this); //注意this用法
using (FileStream fs=new FileStream(sf.FileName,FileMode.Create,FileAccess.Write))
{
fs.Write(receive, 1, realr-1); //-1去掉標志頭
}
}
}
}
public void Msger(string ms)
{
textBox3.AppendText(ms + "\n"); //追加方式
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
}
private void label5_Click(object sender, EventArgs e)
{
}
private void label6_Click(object sender, EventArgs e)
{
}
//客戶端socket
Socket socketcustomsend;
private void button4_Click(object sender, EventArgs e)
{
//創建socket
socketcustomsend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//設置ip和port
IPAddress ip = IPAddress.Parse(textBox5.Text);
IPEndPoint ipendpoint = new IPEndPoint(ip, Convert.ToInt32(textBox6.Text));
//連接
socketcustomsend.Connect(ipendpoint);
textBox4.Text = "連接成功!";
//創建進程接受服務器傳來的信息
Thread th = new Thread(CustomReceive);
th.IsBackground = true;
th.Start(socketcustomsend);
}
/// <summary>
/// 循環接受服務器傳來的信息
/// </summary>
/// <param name="s">通信的socket</param>
public void CustomReceive(object s)
{
while (true) //循環接收信息
{
Socket socketcustomsend = s as Socket;
byte[] b = new byte[1024 * 1024 * 5];
int r = socketcustomsend.Receive(b);
if (r==0) //0表示服務器端關閉
{
break;
}
textBox4.Text = Encoding.UTF8.GetString(b, 0, r);
}
}
private void button2_Click(object sender, EventArgs e)
{
//准備數據
byte[] b = Encoding.UTF8.GetBytes(textBox4.Text);
//加入識別頭0
List<byte> nb = new List<byte>();
nb.Add(0);
nb.AddRange(b);
byte[] sb= nb.ToArray();
//發送
socketcustomsend.Send(sb);
}
private void button6_Click(object sender, EventArgs e)
{
textBox3.Clear();
}
private void button5_Click(object sender, EventArgs e)
{
OpenFileDialog of = new OpenFileDialog();
of.Multiselect = false;
of.Filter = "所有文件|*.*";
of.ShowDialog();
textBox7.Text = of.FileName;
}
private void button3_Click(object sender, EventArgs e)
{
using (FileStream fs = new FileStream(textBox7.Text, FileMode.Open, FileAccess.Read))
{
byte[] b = new byte[1024 * 1024 * 10];
//返回真實使用數
int r = fs.Read(b, 0, b.Length);
//添加文件類型識別頭,list與array互相轉換
List<byte> newbyte = new List<byte>();
newbyte.Add(1);//1代表文件
newbyte.AddRange(b);//將b中元素添加,add()為整個添加
byte[] nb=newbyte.ToArray();
//發送真實大小數據, 為r+1
socketcustomsend.Send(nb,0,r+1,SocketFlags.None);
}
}
private void button7_Click(object sender, EventArgs e)
{
sdic[comboBox1.SelectedItem.ToString()].Send(Encoding.UTF8.GetBytes(textBox3.Text));
}
}
}
