基于C#的TcpSmtpSqlServer的不可名状之物

通过Tcp进行远程连接,SQL server进行数据存储,QQ邮箱发送注册验证码

引言

本文项目可以,在远程主机上通过客户端与服务端的Tcp连接进行通信,然后利用邮箱发送验证码在服务端完成验证并且注册,当验证在服务端通过后,
,服务端将会把用户信息保存在SQL server的数据库中。注意使用QQ在服务端发送消息,需要先在QQ邮箱开启SMTP服务,然后保存授权码。

步骤一:在VisualStudio中创建一个“控制台应用(.net framework)”的新项目FWDBx02。

项目命名为:FWDBx02 。包含四个部分:Program.cs(主体);MailSendControls.cs(邮件控制);SQLcontrols.cs(数据库控制);
ProtocolControls.cs(验证处理控制)。

Program.cs代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;

namespace FWDBx02
{
internal class Program
{
private static List<string> DataList = new List<string>();
private static string asd;
private static string userReturn;
public static string asduserID;
private static string userID;
public static string asduserkeyword;
private static string userkeyword;
private static string CAPTCHAstr;
public static string asdsendMAIL;
private static string sendMAIL;
public static byte[] receiveBuffer = new byte[1024];
public static string receiveSTR;
public static IPAddress ipAddress;
public static int portINT;
public static IPEndPoint iPEndPoint;
public static Socket socket;
static void Main(string[] args)
{

Console.WriteLine("这里是服务端:");
try
{
Console.WriteLine("输入服务器IP:");
ipAddress = IPAddress.Parse(Console.ReadLine());
Console.WriteLine("输入开放端口:");
portINT = int.Parse(Console.ReadLine());
iPEndPoint = new IPEndPoint(ipAddress, portINT);
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(iPEndPoint);

socket.Listen(10);
socket.BeginAccept(AcceptCallback,socket);
}
catch (SocketException se) { Console.WriteLine("MAINse:"+se.Message); }
catch (Exception ex) { Console.WriteLine("MAINex:"+ex.Message); }
Console.ReadKey();
}

private static void AcceptCallback(IAsyncResult ar)
{
try
{
Socket socket = (Socket)ar.AsyncState;
Socket clientSocket = socket.EndAccept(ar);
clientSocket.BeginReceive(receiveBuffer,0,1024,0,ReceiveCallback,clientSocket);
socket.BeginAccept(AcceptCallback, socket);
}
catch (SocketException se) { Console.WriteLine("ACBse:"+se.Message);}
catch (Exception ex) { Console.WriteLine("ACBex:"+ex.Message); }
}

private static void ReceiveCallback(IAsyncResult ar)
{
//try
//{
Socket clientSocket = (Socket)ar.AsyncState;
int con = clientSocket.EndReceive(ar);
receiveSTR = System.Text.Encoding.UTF8.GetString(receiveBuffer, 0, con);
Console.WriteLine(receiveSTR);//*
ProcessingUSER(receiveSTR);
///
clientSocket.BeginReceive(receiveBuffer, 0, 1024, 0, ReceiveCallback, clientSocket);
//}
//catch (SocketException se) { Console.WriteLine("RCBse:"+se.Message);}
//catch (Exception ex) { Console.WriteLine("RCBex:"+ex.Message);}

}

private static void ProcessingUSER(string receiveSTR)
{
ProtocolControls protocolControls = new ProtocolControls(receiveSTR);
CAPTCHAstr = protocolControls.captchaSTR;//用户发送信息第一波产生的验证码
asd = CAPTCHAstr;
sendMAIL = protocolControls.SENDMAIL;
asdsendMAIL = sendMAIL;
userID = protocolControls.USRID;
asduserID = userID;
userkeyword = protocolControls.USRKEYWORD;
asduserkeyword = userkeyword;
DataList.Add(asduserID);
DataList.Add(asduserkeyword);
DataList.Add(asdsendMAIL);
//DataList.Add(CAPTCHAstr);
Console.WriteLine($"{asduserID} {asduserkeyword} {asdsendMAIL}");
//222222/1234565/[email protected]
if (CAPTCHAstr != null)
{
userReturn = protocolControls.USRRETURN;

MailSendControls mailSendControls = new MailSendControls(sendMAIL, CAPTCHAstr);

}else if(userReturn == asd )
{
Console.WriteLine($"{DataList[0]} {DataList[1]} {DataList[2]}");
SQLcontrols sQLcontrols = new SQLcontrols(DataList[0], DataList[1], DataList[2]);
}


}
}
}

MailSendControls.cs代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using System.Net;
using System.Net.Mail;

namespace FWDBx02
{
internal class MailSendControls//注册邮件发送
{
private static string mailLocalAdd = "你的邮箱";
private static string keyword = "SMTP授权码";
private static string SendToMailAdd ;
private static string CAPTCHAstr;
public MailSendControls(string sendToMailAdd,string captchaSTR)
{
SendToMailAdd = sendToMailAdd;
CAPTCHAstr = captchaSTR;
MailSend(SendToMailAdd, CAPTCHAstr);
}
private void MailSend(string SendToMailAdd, string captchaSTR)
{
MailMessage mailMessage = new MailMessage();
mailMessage.From = new MailAddress(mailLocalAdd, "通信ID注册", System.Text.Encoding.UTF8);

mailMessage.To.Add(new MailAddress(SendToMailAdd));
mailMessage.Bcc.Add(new MailAddress(SendToMailAdd));
mailMessage.Subject = "这是邮件的主题";
mailMessage.SubjectEncoding = System.Text.Encoding.UTF8;

mailMessage.IsBodyHtml = false;
mailMessage.Body = $"注册验证码:{captchaSTR}";
mailMessage.BodyEncoding = System.Text.Encoding.UTF8;

SmtpClient smtpClient = new SmtpClient("smtp.qq.com", 587);
smtpClient.EnableSsl = true;
smtpClient.Credentials = new NetworkCredential(mailLocalAdd, keyword);
smtpClient.Send(mailMessage);
}
}
}

SQLcontrols.cs代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System.Data.SqlClient;

namespace FWDBx02
{
internal class SQLcontrols//注册信息存入数据库
{
//连接字符串
private static string serverToDateBase = "Server = localhost;DataBase = TestA02x01;Trusted_Connection = true;";
//sql语句
private static string sqlSTR;
private static string userid;
private static string userkeyword;
private static string usermail;
public SQLcontrols(string Userid,string Userkeyword,string Usermail)
{
sqlSTR = $"insert into userREGTable_1(userid,userkeyword,usermail) values('{Userid}','{Userkeyword}','{Usermail}')";
InsertSQLDB(sqlSTR);
}
private static void InsertSQLDB (string SqlSTR)
{
SqlConnection sqlConnection = new SqlConnection ();
sqlConnection.ConnectionString = serverToDateBase;//先连接,再打开
sqlConnection.Open ();

SqlCommand cmd = sqlConnection.CreateCommand ();
cmd.CommandText = sqlSTR;
cmd.Connection = sqlConnection;
int resultSQL = cmd.ExecuteNonQuery ();
sqlConnection.Close ();
}
}
}

ProtocolControls.cs代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
using System;

namespace FWDBx02
{
internal class ProtocolControls //协议处理,将账号的注册并入协议处理
{
class ProtocolTexts
{
public ProtocolTexts() { }
public string reg = "REG";
public string communication = "COMM";
}

public string captchaSTR;
public string SENDMAIL;
public string USRID;
public string USRKEYWORD;
public string USRRETURN;

private static string receiveSTR;
char splitSTR = '/'; //通过“/”分割信息
private static string[] parts;
private static int partsLength;
public ProtocolControls(string ReceiveSTR)
{
receiveSTR = ReceiveSTR;
/////
//扫描接收信息字节是否有恶意(没写)
/////
ProtocolProcessing(receiveSTR);
}
private void ProtocolProcessing( string receiveSTR)
{
ProtocolTexts protocolTexts = new ProtocolTexts();
parts = receiveSTR.Split(splitSTR);
partsLength = parts.Length;

if (parts[0] == protocolTexts.reg)
{
switch (parts[0])
{
case "REG": goto ZCZH; ; ;
case "COMM": goto ZHTX; ; ;
}
}

ZCZH:

if (parts[1].Length == 4)
{
//SENDMAIL = parts[3];
USRRETURN = parts[1];
captchaSTR = null;////????????????????????????????
goto PT;
}
else
{
//USRRETURN = null;
USRID = parts[1];
USRKEYWORD = parts[2];
SENDMAIL = parts[3];
Random random = new Random();
int[] num = new int[4];
string[] captcha = new string[4];

for (int i = 0; i<4;i++)
{
num[i] = random.Next(0,10); //随机生成数字
captcha[i] = num[i].ToString();
}
captchaSTR = captcha[0]+captcha[1]+captcha[2]+captcha[3];//这是验证码
goto PT;
;
}

ZHTX:

goto PT;
;
PT:// ZCZH 或者 ZHTX 执行完成 后统一 跳转 到 "PT标签"

return ;
}
}
}

步骤二:创建一个“控制台应用(.net framework)”的新项目CHDAx02

项目命名为CHDAx02。该项目只有一个Program.cs文件,唯一需要注意的是socket的使用,它的Beginsend方法及其回调SendCallback与发送方法send。

由于这个代码是以前写的,不是用来做这个的,只是稍稍改了一下,所以有多余部分没有修改删除,不过重点注意上一句话的内容就行了。

Program.cs代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
using System;
using System.Net.Sockets;
using System.Net;

namespace CHDAx02
{
internal class Program //客户端
{
//REGISTRATION:REG(注册请求)
//COMMUNICATION:COMM(通信请求)

public enum Protocol
{
REG = 1110,
COMM = 1111,
}

static IPAddress iPAddress;
public static int portINT ;
static IPEndPoint iPEndPoint ;

public static string receiveSTR;
public static byte[] sendBuffer;
public static byte[] receiveBuffer;
static Socket socket ;

static void Main(string[] args)
{
Console.WriteLine("这里是客户端");
try
{
Console.WriteLine("注意输入用户信息时,格式为 用户id/用户密码/用户邮箱 然后回车,只回车一下,然后等待邮箱接受验证码");
Console.WriteLine("当邮箱接收到验证码后,就可以直接在客户端输入验证码然后回车,若验证码正确,注册完成");
Console.WriteLine("输入服务端IP地址:");
iPAddress = IPAddress.Parse(Console.ReadLine());
Console.WriteLine("输入服务端端口:");
portINT = int.Parse(Console.ReadLine());
Console.WriteLine("输入用户信息:");
iPEndPoint = new IPEndPoint(iPAddress, portINT);
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.BeginConnect(iPEndPoint, ConnectCallback, socket);
while (true)
{
string asd = Console.ReadLine();
Send(Protocol.REG, asd);
}
//*发送信息方法
}
catch (SocketException se) { Console.WriteLine("MainSE:"+se.Message); }
catch (Exception ex) { Console.WriteLine("MainEX:"+ex.Message); }

Console.WriteLine("按任意键关闭");
Console.ReadKey();
}


private static void ConnectCallback(IAsyncResult ar)
{
try
{
Socket clientSocket = (Socket)ar.AsyncState;
clientSocket.EndConnect(ar);
//注释接收
//clientSocket.BeginReceive(receiveBuffer,0,receiveBuffer.Length,0,ReceiveCallback,clientSocket);

}
catch (SocketException se) { Console.WriteLine("CCBse:"+se.Message); }
catch (Exception ex) { Console.WriteLine("CCBex:"+ex.Message); }
}

private static void ReceiveCallback(IAsyncResult ar)
{
try
{
Socket clientSocket = (Socket)ar.AsyncState;
int cont = clientSocket.EndReceive(ar);
receiveSTR = System.Text.Encoding.UTF8.GetString(receiveBuffer, 0, cont);
Console.WriteLine(receiveSTR);//*
clientSocket.BeginReceive(receiveBuffer, 0, receiveBuffer.Length, 0, ReceiveCallback, clientSocket);
}
catch (SocketException se) { Console.WriteLine("RCBse:" + se.Message); }
catch (Exception ex) { Console.WriteLine("RCBex:"+ex.Message); }
}

public static void Send(Protocol protocol,string UserSendSTR) //手动调用//约定协议,协议全部大写
{
try
{
string sendData = protocol + "/" + UserSendSTR;
sendBuffer = System.Text.Encoding.UTF8.GetBytes(sendData);
socket.BeginSend(sendBuffer, 0, sendBuffer.Length, 0, SendCallback, socket);

}
catch (SocketException se) { Console.WriteLine("SendSE:" + se.Message); }
catch (Exception ex) { Console.WriteLine("SendSE:"+ex.Message); }
}

private static void SendCallback(IAsyncResult ar)
{
try
{
Socket socket = (Socket)ar.AsyncState;
int cont = socket.EndSend(ar);
}
catch (SocketException se) { Console.WriteLine("SCBse:" + se.Message); }
catch (Exception ex) { Console.WriteLine("SCBex:"+ex.Message); }
}
}
}

步骤三:如果就只是在本机的端口上使用,那么已经完成。如果想两台电脑远程访问,需要结合路由器的端口映射和cpolar创建隧道,进行进行内网穿透。

当你完成端口映射和隧道创建后:

拥有FWDBx02 项目的作服务端,在输入ip是,应该是你的内网ip,即在cmd中ipconfig看到的ip地址。

而CHDAx02项目则是需要发送给客户端,这里输入的ip应该是路由器的公网ip,需要注意端口要统一。

原理:当客户端访问 路由器公网ip:端口 时,因为有端口映射,所以路由器会把该端口的访问转发到映射的内网ip上的端口上,就完成了通信。

代码很粗糙,我知道,这只是我的一个学习记录而已。