一、IP和端口
1、 IP在网络上为每一台计算机的地址,端口是网络中每台计算机的不同程序访问的入口。
2、 计算机给每个程序绑定一个端口,用于网络访问。
二、套接字
1、应用程序通过系统和网络设备进行交互,微软把这些程序封装成一个socket类,它是程序与外界联系的一个通道,用于描述IP地址和端口,计算机的每个服务都打开一个socket,并绑定到一个端口。
2、就像电话通信方式一样,在通信之前先申请一个socket对象,同时必须知道对方的IP地址和端口号,相当于对方有一个固定的socket,然后向对方发送呼叫,相当于发送连接请求,当一方关闭socket,就相当于关闭两者之间的通信。
3、例:http使用80端口,ftp使用21端口,smtp使用23端口。
4、socket信息的传递方式有两种:
1)基于流的传输(stream):类似于电话,特点是即时性,一方发送,另一方随时接受;
2)基于报文的传输(datagram):类似于写信,特点是不论对方是否准备好,都可以先发送,但也有可能丢失。
5、socket一般应用模式:
1)必须有一个服务端和客户端;
2)先生成一个服务端的套接字用于监听,然后客户端的套接字与服务端“接待套接字”连接;
3)服务端“接待套接字”收到客户端的请求后,启动另外一个“通信套接字”与客户端通信。
6、服务端套接字至少有两个:一个负责接收客户端请求,但不负责通信,在成功接收到客户端请求后,为该客户端创建一个对应的套接字。
7、客户端有一个套接字:必须指定要连接的服务器地址和端口,创建一个socket对象来初始化一个到服务器的TCP连接。
8、通信基本流程图:
1)服务器:创建套接字socket()->绑定监听端口bind()->设置监听队列listen()->循环等待客户连接accept()(如果建立通信,则创建另外一个套接字)->接收数据receive()/发送数据send()/捕获异常->断开通信close();
2)客户端:创建套接字socket()->连接建立connect()->接收数据receive()/发送数据send()>断开通信close()。
9、聊天通信程序:
1)服务器:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;//IPAddress IPEndPoint IP和端口类
using System.Threading;
namespace CommunicationProgram
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
TextBox.CheckForIllegalCrossThreadCalls = false;
}
Thread threadwatch = null; //创建一个用于accept的线程
Socket SocketWatch = null; //负责监听的套接字
//Socket connection = null; //负责通信的套接字
Dictionary<string, Socket> dict = new Dictionary<string, Socket>(); //泛型字典集合
private void btnListen_Click(object sender, EventArgs e)
{
try
{
SocketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //创建套接字:IPv4,流传输,TCP协议
IPAddress address = IPAddress.Parse(txtip.Text.Trim()); //获得IP地址:将IP地址自动转换赋给地址对象
IPEndPoint EndPoint = new IPEndPoint(address, Convert.ToInt32(txtfort.Text)); //创建包含IP和端口的网络节点对象
SocketWatch.Bind(EndPoint); //将负责监听的socket绑定到唯一的节点
SocketWatch.Listen(10); //设置监听队列最大数量为10,超过了就抛出异常
//Socket connection = SocketWatch.Accept(); //创建新的套接字与客户端通信,accept()如果没有接受,则一直在循环等待,可以放在另一个线程中处理
threadwatch = new Thread(watchconnecting); //创建监听线程,并传入监听方法
threadwatch.IsBackground = true; //设置为后台线程
threadwatch.Start(); //开启线程
ShowMessage("服务器启动!");
}
catch(Exception a)
{
MessageBox.Show("error");
}
}
void watchconnecting()
{
while (true) //持续不断地监听客户端的连接请求
{
Socket connection = SocketWatch.Accept();//创建新的套接字与客户端通信,accept()如果没有接受,则一直在循环等待
lbonline.Items.Add(connection.RemoteEndPoint.ToString()); //向列表中添加客户端节点信息,作为唯一标识
dict.Add(connection.RemoteEndPoint.ToString(),connection); //在字典集合中加入此时接入服务器的客户端节点
ShowMessage("客户端连接成功!"+connection.RemoteEndPoint.ToString()); //获取客户端远程IP和端口
}
}
void ShowMessage(string msg)
{
txtmessage.AppendText(msg + "\r\n");
}
private void btnsend_Click(object sender, EventArgs e)
{
try
{
string SendMsg = txtsend.Text.Trim();
byte[] arr = System.Text.Encoding.UTF8.GetBytes(SendMsg);//将字符串转换为utf8字节数组
string strclient = lbonline.Text; //获得列表中选中的客户端远程节点
dict[strclient].Send(arr); //通过节点找到字典集合中对应的客户端套接字,并调用send方法发送数据
//connection.Send(arr);//发送数据
ShowMessage("发送数据" + SendMsg);
}
catch (Exception j)
{
MessageBox.Show("error");
}
}
/// <summary>
/// 群发
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnall_Click(object sender, EventArgs e)
{
string SendMsg = txtsend.Text.Trim();
byte[] arr = System.Text.Encoding.UTF8.GetBytes(SendMsg);//将字符串转换为utf8字节数组
for (int i = 0; i < lbonline.Items.Count; i++)
{
dict[lbonline.Items[i].ToString()].Send(arr);
}
}
}
}
2)客户端:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace ClientApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
TextBox.CheckForIllegalCrossThreadCalls = false;
}
Thread receive = null;
Socket client = null;
byte[] remsg = null;
string remsgg = null;
private void btnconnect_Click(object sender, EventArgs e)
{
try
{
IPAddress address = IPAddress.Parse(txtip.Text.Trim());
IPEndPoint endpoint = new IPEndPoint(address, int.Parse(txtfort.Text.Trim()));
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.Connect(endpoint);
receive = new Thread(receivemsg);
receive.IsBackground = true;
receive.Start();
}
catch (Exception t)
{
MessageBox.Show("error");
}
//ShowMessage("");
}
void receivemsg()
{
while (true)
{
remsg = new byte[1024 * 1024 * 2];
int length = client.Receive(remsg); //接收服务器传来的数据,并返回真正接收到的数据长度
remsgg = System.Text.Encoding.UTF8.GetString(remsg,0,length);
ShowMessage(remsgg);
}
}
void ShowMessage(string msg)
{
txtmessage.AppendText(msg + "\r\n");
}
}
}
3)服务端循环监听:在监听方法中加入while(true)循环。
---------------------- ASP.Net+Android+IOS开发、 .Net培训、期待与您交流! ----------------------