C#基础学习笔记(十五)
1.复习
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//用来存储音乐文件的全路径
List<string> listSongs = new List<string>();
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Title = "请选择音乐文件";
openFileDialog.InitialDirectory = @"D:\示例图片";
openFileDialog.Multiselect = true;
openFileDialog.Filter = "音乐文件|*.wav|所有文件|*.*";
openFileDialog.ShowDialog();
//获得选择文件夹中的选择的文件
string[] path = openFileDialog.FileNames;
for (int i = 0; i < path.Length; i++)
{
listBox1.Items.Add(Path.GetFileName(path[i]));
listSongs.Add(path[i]);
}
}
SoundPlayer soundPlayer = new SoundPlayer();
private void listBox1_DoubleClick(object sender, EventArgs e)
{
soundPlayer.SoundLocation = listSongs[listBox1.SelectedIndex];
soundPlayer.Play();
}
private void button3_Click(object sender, EventArgs e)
{
//获取当前选中歌曲的索引
int index = listBox1.SelectedIndex;
index++;
if (index == listBox1.Items.Count)
{
index = 0;
}
//将改变后的索引重新的赋值给当前选中项的索引
listBox1.SelectedIndex = index;
soundPlayer.SoundLocation = listSongs[index];
soundPlayer.Play();
}
private void button2_Click(object sender, EventArgs e)
{
int index = listBox1.SelectedIndex;
index--;
if (index < 0)
{
index = listBox1.Items.Count - 1;
}
//将改变后的索引重新的赋值给当前选中项的索引
listBox1.SelectedIndex = index;
soundPlayer.SoundLocation = listSongs[index];
soundPlayer.Play();
}
}
2.线程和进程的复习
2.1 Thread类
- Start(); 启动线程
- Abort(); 终止线程,而且不能再Start
2.2 线程中如何访问控件
//取消跨线程的访问
Control.CheckForIllegalCrossThreadCalls = false;
2.3 执行带参数的方法
如果线程执行的方法需要参数,那么要求这个参数必须是object类型。
3.摇奖机
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
bool b = false;
private void button1_Click(object sender, EventArgs e)
{
//PlayGame();
if (b == false)
{
b = true;
button1.Text = "停止";
Thread th = new Thread(PlayGame);
th.IsBackground = true;
th.Start();
}
else
{
b = false;
button1.Text = "开始";
}
}
private void PlayGame()
{
Random r = new Random();
while (b)
{
label1.Text = r.Next(0, 10).ToString();
label2.Text = r.Next(0, 10).ToString();
label3.Text = r.Next(0, 10).ToString();
}
}
private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
}
}
4.SOCKET网络编程
4.1 概述
人通过【电话】可以通讯
程序通过【Socket】来通讯
Socket就是程序间的电话机
- 我和其他人打电话 电话 规定好的语言
- 电脑和电脑进行联系 协议UDP/TCP
4.2 Socket相关概念
- socket的英文原义是“孔”或“插座”。作为进程通信机制,取后一种意思。通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄。(其实就是两个程序通信用的。)
- socket非常类似于电话插座。以一个电话网为例。电话的通话双方相当于相互通信的2个程序,电话号码就是IP地址。任何用户在通话之前,首先要占有一部电话机,相当于申请一个socket;同时要知道对方的号码,相当于对方有一个固定的socket。然后向对方拨号呼叫,相当于发出连接请求。对方假如在场并空闲,拿起电话话筒,双方就可以正式通话,相当于连接成功。双方通话的过程,是一方向电话机发出信号和对方从电话机接收信号的过程,相当于向socket发送数据和从socket接收数据。通话结束后,一方挂起电话机相当于关闭socket,撤消连接。
可以结合找人的示例,形象的理解,服务器端的门卫(负责监听的Sockt),知道了访问请求就会创建一个负责通讯的Socket
4.3 Socket相关概念[端口]
-
在Internet上有很多这样的主机,这些主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务(应用程序)。
-
例如:http 使用80端口 ftp使用21端口 smtp 25端口
-
有两种类型:50000
-
-
流式Socket(STREAM):
是一种面向连接的Socket,针对于面向连接的TCP服务应用,安全,但是效率低; -
数据报式Socket(DATAGRAM):
是一种无连接的Socket,对应于无连接的UDP服务应用.不安全(丢失,顺序混乱,在接收端要分析重排及要求重发),但效率高.
-
一般使用的就是TCP,会有3次握手
客户端:你有空吗?
服务端:我有空
客户端:我知道你有空了
安全稳定,但是效率慢
UDP快速,效率高,但是不稳定,容易发生数据丢失
4.4 Socket一般应用模式(服务器端和客户端)
1.服务端welcoming socket 开始监听端口(负责监听客户端连接信息)
2.客户端client socket连接服务端指定端口(负责接收和发送服务端消息)
3.服务端welcoming socket 监听到客户端连接,创建connection socket。(负责和客户端通信)
示例:
服务器:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
/*
服务端 客户端
| |
Socket() |
| |
Bind()绑定监听端口 |
| |
Listen()设置监听队列 |
| |
while{Accept()}循环等待客户端连接<———————>Connect()建立连接
| |
Receive()<—————————————————————————————Sned()发送数据
| |
Send()———————————————————————————————>Receive()接收数据
| |
捕捉异常<——————————————————————————————Close()发送数据
|
Close()
*/
private void btnStart_Click(object sender, EventArgs e)
{
try
{
//创建一个负责监听的
//SocketType是流式的Stream 对应的就是tcp
//数据报式DATAGRAM 对于的是UTP
Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//创建IP地址和端口号对象
//不要写死,要不然更换的时候就不好用了
IPAddress ip = IPAddress.Any;//IPAddress.Parse(txtServer.Text);
IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));
//让负责监听的Socket绑定IP地址和端口号
socketWatch.Bind(point);
ShowMsg("监听成功");
//设置监听队列 就是同一时间可以链接的最大客户端数量
socketWatch.Listen(10);
Thread th = new Thread(Listen);
th.IsBackground = true;
th.Start(socketWatch);
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// 等待客户端的连接 并且创建与之通信用的Socket
/// </summary>
/// <param name="o">线程带参数,进来强转</param>
Socket socketSend;
void Listen(object o)
{
Socket socketWatch=o as Socket;
//负责监听的Socket来接受客户端的连接,创建跟客户端通信的Socket
while (true)
{
try
{
//负责跟客户端通信的Socket
socketSend = socketWatch.Accept();
//将远程连接的客户端的IP的地址和Socket存入集合
dicSocket.Add(socketSend.RemoteEndPoint.ToString(), socketSend);
//将远程连接的客户端的IP地址和端口号存储下拉框中
cboUsers.Items.Add(socketSend.RemoteEndPoint.ToString());
ShowMsg(socketSend.RemoteEndPoint.ToString() + "连接成功");
//开启一个新线程不停的接受客户端发送过来的消息
Thread th = new Thread(Recive);
th.IsBackground = true;
th.Start(socketSend);
}
catch (Exception)
{
throw;
}
}
}
//将远程连接的客户端的IP的地址和Socket存入集合
Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();
/// <summary>
/// 服务器不停的接受客户端发过来的信息
/// </summary>
/// <param name="o">线程带参数</param>
void Recive(object o)
{
Socket socketSend = o as Socket;
while (true)
{
try
{
//写在Listen里边执行一边以后会等待新的接受,单独写一个方法循环
//客户端连接后,服务器应该接受客户端发来的消息
byte[] buffer = new byte[1024 * 1024 * 2];
//实际接收到的有效字节数
int r = socketSend.Receive(buffer);
if (r == 0) break;
string str = Encoding.UTF8.GetString(buffer, 0, r);
ShowMsg(socketSend.RemoteEndPoint + ":" + str);
}
catch (Exception)
{
throw;
}
}
}
/// <summary>
/// 显示信息
/// </summary>
/// <param name="str"></param>
void ShowMsg(string str)
{
txtLog.AppendText(str + "\r\n");
}
private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
}
/// <summary>
/// 服务器给客户端发送消息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSend_Click(object sender, EventArgs e)
{
string str = txtMsg.Text;
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
//现在想要实现其他的功能 在这些buffer前面加上定义的标识符
List<byte> list = new List<byte>();
list.Add(0);
list.AddRange(buffer);
//将泛型集合转换为数组
buffer = list.ToArray();
//byte[] newBuffer = list.ToArray();
//socketSend.Send(buffer);
//获得用户在下拉框选中的IP地址
string ip = cboUsers.SelectedItem.ToString();
dicSocket[ip].Send(buffer);
}
/// <summary>
/// 选择要发送的文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSelect_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.InitialDirectory = @"D:\示例图片";
ofd.Title = "请选择要发送的文件";
ofd.Filter = "所有文件|*.*";
ofd.ShowDialog();
txtPath.Text = ofd.FileName;
}
private void btnSendFile_Click(object sender, EventArgs e)
{
//获得要发送文件的路径
string path = txtPath.Text;
using (FileStream fsRead = new FileStream(path, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[1024 * 1024 * 5];
int r = fsRead.Read(buffer, 0, buffer.Length);
List<byte> list = new List<byte>();
list.Add(1);
list.AddRange(buffer);
byte[] newbuffer = list.ToArray();
dicSocket[cboUsers.SelectedItem.ToString()].Send(newbuffer, 0, r + 1, SocketFlags.None);
}
}
/// <summary>
/// 发送震动
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnZD_Click(object sender, EventArgs e)
{
byte[] buffer = new byte[1];
buffer[0] = 2;
dicSocket[cboUsers.SelectedItem.ToString()].Send(buffer);
}
}
客户端:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Socket socketSend;
private void btnStart_Click(object sender, EventArgs e)
{
try
{
//创建负责通信的Socket
socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse(txtServer.Text);
IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));
//获得要连接的远程服务器应用程序的IP地址和端口号
socketSend.Connect(point);
ShowMsg("连接成功");
//开启一个新的线程不停的接受服务端发来的消息
Thread th = new Thread(Recive);
th.IsBackground = true;
th.Start();
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// 不停的接受服务器发来的消息
/// </summary>
void Recive()
{
while (true)
{
try
{
byte[] buffer = new byte[1024 * 1024 * 3];
//实际接收到的有效字节
int r = socketSend.Receive(buffer);
if (r == 0)
{
break;
}
//表示发送的文字消息
if (buffer[0] == 0)
{
string s = Encoding.UTF8.GetString(buffer, 1, r - 1);
ShowMsg(socketSend.RemoteEndPoint + ":" + s);
}
else if (buffer[0] == 1)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.InitialDirectory = @"D:\示例图片\测试";
sfd.Title = "请选择要保存的文件";
sfd.Filter = "所有文件|*.*";
sfd.ShowDialog(this);
string path = sfd.FileName;
using (FileStream fsWrite = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write))
{
fsWrite.Write(buffer, 1, r - 1);
}
MessageBox.Show("保存成功");
}
else if (buffer[0] == 2)
{
ZD();
}
}
catch (Exception)
{
throw;
}
}
}
/// <summary>
/// 震动
/// </summary>
void ZD()
{
for (int i = 0; i < 500; i++)
{
this.Location = new Point(200, 200);
this.Location = new Point(280, 280);
}
}
void ShowMsg(string str)
{
txtLog.AppendText(str + "\r\n");
}
/// <summary>
/// 客户端给服务器发送消息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSend_Click(object sender, EventArgs e)
{
string str = txtMsg.Text.Trim();
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
socketSend.Send(buffer);
}
private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
}
}