Socket的通讯过程
服务器端:
01,申请一个socket
02,绑定到一个IP地址和一个端口上
03,开启侦听,等待接收连接
客户端:
01,申请一个socket
02,连接服务器(指明IP地址和端口号)
服务器端接收到连接请求后,产生一个新的socket(端口大于1024)与客户端建立连接并进行通信,原监听socket继续监听。
注意:负责通信的Socket不能无限创建,创建的数量和操作系统有关。
7.Socket的构造函数
Public Socket(AddressFamily addressFamily,SocketType socketType,ProtocolType protocolTYpe)
AddressFamily:指定Socket用来解析地址的寻址方案。例如:InterNetWork指示当Socket使用一个IP版本4地址连接
SocketType:定义要打开的Socket的类型
Socket类使用ProtocolType枚举向Windows Sockets API通知所请求的协议
注意:
1,端口号必须在 1 和 65535之间,最好在1024以后。
2,要连接的远程主机必须正在监听指定端口,也就是说你无法随意连接远程主机。
3,如果只是在当前电脑上上运行需要使用127.0.0.1ip地址,192.x.x.x的需要使用网线连接其他主机。
如:
IPAddress addr = IPAddress.Parse("127.0.0.1");
IPEndPoint endp = new IPEndPoint(addr,,9000);
服务端先绑定:serverWelcomeSocket.Bind(endp)
客户端再连接:clientSocket.Connect(endp)
3,一个Socket一次只能连接一台主机
4,Socket关闭后无法再次使用
5,每个Socket对象只能与一台远程主机连接。如果你想连接到多台远程主机,你必须创建多个Socket对象。
8.Socket常用类和方法
相关类:
IPAddress:包含了一个IP地址
IPEndPoint:包含了一对IP地址和端口号
方法:
Socket():创建一个Socket
Bind():绑定一个本地的IP和端口号(IPEndPoint)
Listen():让Socket侦听传入的连接吃那个病,并指定侦听队列容量
Connect():初始化与另一个Socket的连接
Accept():接收连接并返回一个新的Socket
Send():输出数据到Socket
Receive():从Socket中读取数据
Close():关闭Socket,销毁连接
接下来,我们同一个简单的服务器和客户端通信的案例,来看下Sokcet的具体用法,效果图如下:
下面是实现的代码功能:
编写工具:VS2015
服务器代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
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 SocketServer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//关闭跨线程访问
Control.CheckForIllegalCrossThreadCalls = false;
}
private void Form1_Load(object sender, EventArgs e)
{
}
//获取通信用的Socekt
Dictionary<string, Socket> dic = new Dictionary<string, Socket>();
//消息显示
void showlog(string str)
{
TB_Info_receive.AppendText(str+"\r\n");
}
/// <summary>
/// 创建实时等待客户端连接的套接字
/// </summary>
/// <param name="o"></将套接字传递到创建连接上面去>
void AcceptInfo(object o)
{
Socket socket = o as Socket;
while (true)
{
try
{
Socket AcSocket= socket.Accept();
//获取远程客户端的IP和端口号
string point = AcSocket.RemoteEndPoint.ToString();
showlog(point + "连接成功");
//往客户端列表里面追加客户端
ComB_Connet_ClientNum.Items.Add(point);
//往纪律通讯的键和值里面追加连接的客户端信息
dic.Add(point,AcSocket);
//接受消息
Thread AC = new Thread(receiver);
AC.IsBackground = true;
AC.Start(AcSocket);
}
catch (Exception ex)
{
showlog(ex.Message);
break;
}
}
}
/// <summary>
/// 接受消息
/// </summary>
/// <param name="o"></将通讯的套接字传送到接受消息创建接受消息的套接字>
private void receiver(Object o)
{
Socket client = o as Socket;
while (true)
{
try
{
//定义一个接收的BUffer存放客户端发送过来的数据
byte[] buffer = new byte[1024 * 1024];
//将接收过来的数据存放再buffer里面,并且返回接受的实际数据长度
int Num = client.Receive(buffer);
//将字节转换成字符串
string words = Encoding.UTF8.GetString(buffer, 0, Num);
showlog(client.RemoteEndPoint.ToString() + ":" + words);
}
catch (Exception ex)
{
showlog(ex.Message);
break;
}
}
}
private void button2_Click(object sender, EventArgs e)
{
try
{
showlog(TB_Info_Send.Text);
string ip = ComB_Connet_ClientNum.Text;
byte[] buffer = Encoding.UTF8.GetBytes(TB_Info_Send.Text);
dic[ip].Send(buffer);
}
catch (Exception ex)
{
showlog(ex.Message);
}
}
private void button1_Click(object sender, EventArgs e)
{
//获取窗口的IP和端口号
IPAddress ip = IPAddress.Parse(TB_Server_ip.Text);
IPEndPoint point = new IPEndPoint(ip, int.Parse(TB_point.Text));
//创建套接字以及设置参数
//创建监听用的Socket
/* AddressFamily.InterNetWork:使用 IP4地址。
SocketType.Stream:支持可靠、双向、基于连接的字节流,而不重复数据。此类型的 Socket 与单个对方主机进行通信,并且在通信开始之前需要远程主机连接。Stream 使用传输控制协议 (Tcp) ProtocolType 和 InterNetworkAddressFamily。
ProtocolType.Tcp:使用传输控制协议。
使用IPv4地址,流式socket方式,tcp协议传递数据
创建好socket后,必须告诉socket绑定的IP地址和端口号。
*/
//让socket监听point
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
//绑定端口号
socket.Bind(point);
//监听端口号以及 设置监听的最大个数
socket.Listen(10);
showlog("服务器开始监听");
Thread thread = new Thread(AcceptInfo);
thread.IsBackground = true;
thread.Start(socket);
}
catch (Exception ex)
{
showlog(ex.Message);
}
}
}
}
客户端实现代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
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 ScoketClient
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}
Socket Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private void BT_statrconnet_Click(object sender, EventArgs e)
{
IPAddress ip = IPAddress.Parse(TB_Server_ip.Text);
IPEndPoint point = new IPEndPoint(ip, int.Parse(TB_point.Text));
Client.Connect(point);
showlog("连接成功");
showlog("服务器" + Client.RemoteEndPoint.ToString());
showlog("客户端" + Client.LocalEndPoint.ToString());
Thread thread = new Thread(receiver);
thread.IsBackground = true;
thread.Start();
}
private void receiver()
{
while (true)
{
try
{
byte[] buffer = new byte[1024 * 1024];
int Num = Client.Receive(buffer);
string s = Encoding.UTF8.GetString(buffer, 0, Num);
showlog(Client.RemoteEndPoint.ToString() + ":" + s);
}
catch (Exception ex)
{
showlog(ex.Message);
break;
}
}
}
void showlog(string str)
{
TB_Info_receive.AppendText(str + "\r\n");
}
private void Form1_Load(object sender, EventArgs e)
{
}
/// <summary>
/// 发送消息给服务器
/// </summary>
/// <param name="sender"></种类>
/// <param name="e"></种类的个数>
private void BT_send_info_Click(object sender, EventArgs e)
{
if (Client!=null)
{
try
{
showlog(TB_Info_Send.Text);
byte[] buffer = Encoding.UTF8.GetBytes(TB_Info_Send.Text);
Client.Send(buffer); }
catch (Exception ex)
{
showlog(ex.Message);
}
}
}
}
}