现在网络的应用越来越普及,网络的构建也越来越简便,对于某些研究性项目自建网络服务端
也是可行的方案。本项目的网络服务,是用C#,基于Socket构建的,核心的工作是通过自定的BS60传输协议,实现与手机端,PC端的数据传输。服务端有两个基本数据表,一个是用户注册表,一个是用户在线数据表。数据管理系统,主要处理网络任务数据,网友分享数据。采用PC机,基于Socket的网络服务,用WIFI局域网就可以进行开发测试,外网要通过内网穿透技术。以下扼要介绍一下服务端的基本架构及邮箱验证和手机验证。
      (一),用C#构建基于Socket网络服务
            网络服务的用户监听,项目开始有两种模式,一个是ASYNC 模式,一个是Thread 模式,后来一直采用的是Thread 模式。除了基本的通用架构,服务端主要是处理(接收及发送)手机端及PC端的数据请求。
          1),网络服务的基本架构

      //获取本机IP地址public List<string> getIP(){List<string> listIP = new List<string>();try{string HostName = Dns.GetHostName(); //得到主机名IPHostEntry IpEntry = Dns.GetHostEntry(HostName);for (int i = 0; i < IpEntry.AddressList.Length; i++){//从IP地址列表中筛选出IPv4类型的IP地址//AddressFamily.InterNetwork表示此IP为IPv4,//AddressFamily.InterNetworkV6表示此地址为IPv6类型if (IpEntry.AddressList[i].AddressFamily == AddressFamily.InterNetwork){listIP.Add(IpEntry.AddressList[i].ToString());}}return listIP;}catch (Exception ex){MessageBox.Show("获取本机IP出错:" + ex.Message);listIP.Clear();return listIP;}}//  启动网络服务监听private Thread threadWatch = null;//负责监听客户端连接请求的线程private Socket socketWatch = null;//负责监听的套接字int READBUFFERSIZE = 1024 * 1024;private void startSeverThread(){// 创建一个基于IPV4的TCP协议的Socket对象if (socketWatch == null){socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);}else{return;}//取得IP地址string strIPaddress = "";List<string> listIP = getIP();if (listIP.Count == 0){//  未能获取IP!return;}else if (listIP.Count >= 1){strIPaddress = listIP[0];}IPAddress ip = IPAddress.Parse(strIPaddress));//创建一个网络端点string strPort = "8899";IPEndPoint ippoint = new IPEndPoint(ip, int.Parse(strPort));//把负责监听的套接字绑定到唯一的IP和端口socketWatch.Bind(ippoint);//设置监听队列的长度socketWatch.Listen(10);threadWatch = new Thread(WatchConnection);threadWatch.IsBackground = true;//设置为后台threadWatch.Start();// 启动线程}// 用户SOCKET 结构  struct userSocket{public Socket curSocket;public int iposj;// 在线用户表的位置}// 监听客户端连接请求的线程void WatchConnection(){while (true){//创建监听的连接套接字Socket sockConnection = socketWatch.Accept();// 创建连接成功添加到 Online User manager 对象里面// 将 IP ADDRESS 转换成 Long 数据long Ipvalue = GetIpLongVale(sockConnection.RemoteEndPoint.ToString());// 将当前访问时间存到 int 数据中 int icTimes = GetLnkServerTime();// 将访问信息添加到在线用户表中int icposj = onLineUserManager.AppendOnlineUser(0, sockConnection, Ipvalue, icTimes);// 创建用户线程 参数传递结构userSocket cLnkuser = new userSocket();//为客户端套接字连接开启新的线程用于接收客户端发送的数据cLnkuser.curSocket = sockConnection;cLnkuser.iposj = icposj;// 创建接收数据的线程Thread t = new Thread(RecMsg);//设置为后台线程t.IsBackground = true;//为客户端连接开启线程t.Start((object)cLnkuser);}2),接收处理客户端数据的线程这一部分是每个项目的核心,不同的项目处理的方式方法也可能不同,本项目处理方式如下。/// 接收客户端信息的线程部分代码void RecMsg(object o){userSocket curStruct = (userSocket)o;Socket socketClient = curStruct.curSocket;int icurposj = curStruct.iposj;Boolean loopRecvblv = true;//创建一个字节数组接收数据byte[] arrMsgRec = new byte[READBUFFERSIZE];byte[] recArrFastReply = new byte[256];// 通过在线用户管理,协调控制数据的接收与发送onLineUserManager.checkSetOnlineUser(icurposj, SET_RECEIVE_RUN);// 设置接收运行onLineUserManager.TaskRecReplyCtrl(icurposj, REPLY_INIT_SET);// 任务接收初始设置Boolean crecLockblv = false;// 接收数据锁保护int iheartBeatTimenum = 0;// 心跳包数onLineUserManager.checkResetThreadLoopWait();while (loopRecvblv){// 设置循环等待参数,可根据在线用户数自动调整Thread.Sleep(onLineUserManager.mThreadLoopSpaceMisec);// 检查用户是否在线if (!onLineUserManager.checkUserIfOnlineblv(icurposj)) break;// 用户离线if (crecLockblv)// 一项数据接收完前循环等待{Thread.Sleep(ConstStringIntDataClass.CYBERLOOPWAIT_RECEIVE);continue;}// 等待快速回应if (onLineUserManager.TaskRecReplyCtrl(icurposj, REPLYOPER_ITEM) != REPLY_EMPTY){// reply user task if (onLineUserManager.TaskRecReplyCtrl(icurposj, REPLYOPER_STATUS) != REPLY_FINISH){Thread.Sleep(20);continue;}crecLockblv = true;// 接收控制锁int length = socketClient.Receive(recArrFastReply);if (length >= 10)// 接收回应数据{// 检查处理回应的数据//  。。。。。。。   }crecLockblv = false;// 数据接收完成开锁continue;}// 正常等待接收数据crecLockblv = true;// 数据接收锁try{//接收数据mReceiveSumn = 0;// 重置本次接收的字节数int length = socketClient.Receive(arrMsgRec);if (length > 0)// 接收到数据{int icgLen = length;if (icgLen > 20) icgLen = 20;// 检查是否是数据头int iretcd = mglobal_checkDataHead(arrMsgRec, length);if (iretcd == DATAKIND_ERROR){// 不是合法数据crecLockblv = false;continue;}if (iretcd == DATAKIND_HEARTBEAT){// 接收到心跳包onLineUserManager.checkSetOnlineUser(icurposj, APPENDOPER_HEARTBEAT);crecLockblv = false;continue;}// 数据一次接收完成if (iretcd == DATAKIND_FINISH){// 处理完成的接收数据// 。。。。crecLockblv = false;continue;}// 数据接收未完成try{while (true){// 继续读入数据length = socketClient.Receive(arrMsgRec);// 添加接收的数据,并检查是否接收完成,接收完成后,退出// 。。。 }// 处理接收的数据crecLockblv = false;}catch (Exception e){// 用户掉线或离开!loopRecvblv = false;break;}}}}catch (Exception e){// 用户掉线或离开!loopRecvblv = false;break;}// 无数据或数据处理完成,继续循环等待crecLockblv = false;}onLineUserManager.checkSetOnlineUser(icurposj, SET_RECEIVE_STOP);// 设置停止接收数据onLineUserManager.removeOnlineUser(icurposj);//关闭套接字,退出监听socketClient.Close();//结束当前线程Thread.CurrentThread.Abort();arrMsgRec = null;}

3), 数据的发送
          项目数据的发送,依据客户端的请求不同,具体的处理流程也是不同的,这里只给处最底层的部分代码。

public void bs60Send(Socket socket, byte[] buffer, int offset, int size, int timeout, int onLineposj){int startTickCount = Environment.TickCount;int sent = 0;  // 已经发送的字节数do{if (Environment.TickCount > startTickCount + timeout)throw new Exception("发送超时");try{sent += socket.Send(buffer, offset + sent, size - sent, SocketFlags.None);}catch (SocketException ex){if (ex.SocketErrorCode == SocketError.WouldBlock ||ex.SocketErrorCode == SocketError.IOPending ||ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable){// 缓冲区可能已满,等待并重试Thread.Sleep(30);}elsethrow ex;  // 发生任何严重错误}} while (sent < size);if (sent >= size){// 发送完成}else{//  发送失败!}}

(二),PC客户端的邮箱验证
       网络服务中,对于PC端的用户通常采用邮箱验证方式,在此提供部分代码供参考。
      进行邮箱验证,首先要选择一个已经开通了SMTP功能的电子邮箱,项目中使用的163的邮箱。

 public static string Email163SmtpSend(string senderName, string toEmail, string copyEmail, string emailTitle, string emailBody){String fromEmail = "xxxxxx@163.com";// string smtpServer = "smtp.163.com";string smtpasswd = "h163126";MailMessage msg = new MailMessage();//邮件信息类msg.From = new MailAddress(fromEmail, senderName, Encoding.UTF8);//邮箱,发件人,编码msg.To.Add(toEmail);//收件人,可以循环添加收件人if (copyEmail.Length > 6){msg.CC.Add(copyEmail);//抄送人,同上}msg.Subject = emailTitle;//邮件主题msg.BodyEncoding = Encoding.UTF8;//邮件内容编码msg.SubjectEncoding = Encoding.UTF8;//邮件主题编码msg.IsBodyHtml = false;//是否是html格式msg.Body = emailBody;msg.Priority = MailPriority.High;//邮件优先级SmtpClient client = new SmtpClient();// 客户端smtpclient.DeliveryMethod = SmtpDeliveryMethod.Network;//指定邮件发送方式为网络client.Host = smtpServer;// 指定服务器client.EnableSsl = false;//服务器支持安全连接,安全为trueclient.UseDefaultCredentials = false;//是否随着请求一起发client.Credentials = new NetworkCredential(fromEmail, smtpasswd);//用户名密码string strInforet = "";try{client.Send(msg);strInforet = "发送成功!";}catch (Exception){strInforet = "发送失败!";}return strInforet;}

(三),移动端的手机验证
          网络服务中的手机验证码发送,是通过“验证服务手机”的专用APP,协同网络服务端手机验证程序完成的。架构是服务端设置一个专用网络数据接口,启动专用 监听程序,处理验证服务手机的登录。移动端开发了一个专用的连网登录及接收验证发送任务的APP程序。
     1), C# 网络端手机验证码发送的部分代码
     这部分就是向已经通过端口连接的验证服务手机,发送服务端生成的手机验证码相关数据(接收验证码的手机号及验证码)

   public class VerifyPhone{// 保存验证用手机的相关信息:套接字与接收缓存public Socket socket;public byte[] Rcvbuffer;//实例化方法public VerifyPhone(Socket s){socket = s;}//清空接受缓存,新的接收之前要调用该方法public void ClearBuffer(){Rcvbuffer = new byte[1024];}//public void Dispose(){try{socket.Shutdown(SocketShutdown.Both);socket.Close();}finally{socket = null;Rcvbuffer = null;}}}// 验证服务程序class SocketServerVerifyClass{// 监听的套接字TcpListener listener;// 是否启动连接了发送验证码的手机bool IsVerifyStart = false;public List<VerifyPhone> phoneLst = new List<VerifyPhone>();// 设置启动端口监听public void Start(string strIPaddress, int intPort){if (IsVerifyStart)return;//服务器启动监听IPEndPoint localep = new IPEndPoint(IPAddress.Parse(strIPaddress), intPort);listener = new TcpListener(localep);listener.Start(10);IsVerifyStart = true;AsyncCallback callback = new AsyncCallback(AcceptCallBack);listener.BeginAcceptSocket(callback, listener);}private void AcceptCallBack(IAsyncResult ar){try{// 完成异步接收连接请求的异步调用// 连接信息添加到手机列表Socket handle = listener.EndAcceptSocket(ar);VerifyPhone vphone = new VerifyPhone(handle);phoneLst.Add(vphone);AsyncCallback callback;// 调用异步方法接收连接请求if (IsVerifyStart){callback = new AsyncCallback(AcceptCallBack);listener.BeginAcceptSocket(callback, listener);}// 连接上进行异步的数据接收vphone.ClearBuffer();callback = new AsyncCallback(ReceiveCallback);vphone.socket.BeginReceive(vphone.Rcvbuffer, 0, vphone.Rcvbuffer.Length, SocketFlags.None, callback, vphone);}catch{// 在调用引发异常,套接字Listener被关闭,设置为未启动侦听状态IsVerifyStart = false;}}private void ReceiveCallback(IAsyncResult ar){VerifyPhone vphone = (VerifyPhone)ar.AsyncState;try{int i = vphone.socket.EndReceive(ar);if (i == 0){RemoveClient(vphone);return;}else{vphone.ClearBuffer();AsyncCallback callback = new AsyncCallback(ReceiveCallback);vphone.socket.BeginReceive(vphone.Rcvbuffer, 0, vphone.Rcvbuffer.Length, SocketFlags.None, callback, vphone);}}catch{}}public void SendData(VerifyPhone vphone, string data){byte[] byteAr = Encoding.UTF8.GetBytes(data);try{AsyncCallback callback = new AsyncCallback(SendCallback);frd.socket.BeginSend( byteAr, 0,  byteAr.Length, SocketFlags.None, callback,vphone);}catch(SocketException ex) {}}private void SendCallback(IAsyncResult ar){VerifyPhone vphone = (VerifyPhone)ar.AsyncState;vphone.socket.EndSend(ar);}private void RemoveClient(VerifyPhone vphone){foreach (VerifyPhone curphone in phoneLst){if (curphone == vphone){phoneLst.Remove(vphone);}}}public void RemoveAllClient(){foreach (VerifyPhone curphone in phoneLst){phoneLst.Remove(curphone);}}public void Stop(){if (!IsVerifyStart)return;listener.Stop();IsVerifyStart = false;}}

// 启动运行 验证码服务程序
    SocketServerVerifyClass verifyServer = new SocketServerVerifyClass();
    // 启动服务监听
    string strIPaddress = getIP();// 得到IP地址
    string verifyPort = "8805";// 专用端口
    verifyServer.Start(strIPaddress, int.Parse(verifyPort));
    // 验证码的发送处理过程
    服务端收到手机验证申请后
    A,自动生成一个随机手机验证码;
    B,检查是否连接了验证码发送手机,没有则向申请注册手机发送现在不能注册的提示;
    C,构建验证码发送数据:string strSendSMS = "bs60SMSPhone:" + 手机号 + "," + 验证码;
    D,通过运行验证服务程序(verifyServer) 发送验证码到验证服务手机
         verifyServer.SendData((VerifyPhone)phoneLst[0], strSendSMS);
    E,同时也向申请验证的手机发送验证码(注,手机的验证是在移动端完成的)。
    2),验证服务手机的验证码接收及发送APP
        任何一部安装安装了Android“手机验证码发送服务APP”的手机,都可以成为“验证服务手机”。
        在手机端同样通过Socket进行网络数据接收与发送。发送部分是保持活动在线的心跳包。下面是java语言的部分代码。

        // 网络连接
private void doConnect() {//子线程请求网络new Thread(new Runnable() {@Overridepublic void run() {String strname = "服务器连接....";try {msocket = new Socket();// 用服务端IP地址和端口号,建立Socket连接String serverIP = "192.168.1.188";// 服务器端IPString serverPort = "8805";// 服务器端口号int icport = Integer.valueOf(serverPort);msocket.connect(new InetSocketAddress(serverIP, icport), 5 * 1000);bos = new BufferedOutputStream(msocket.getOutputStream());// 启动监听,读取网络数据readThread = new ReadThread();readThread.start();strname = "服务器连接成功!";isconnectBoolean=true;// 启动心跳包new Thread(new KeepAliveHeartBeat()).start();} catch (Exception e) {e.printStackTrace();strname = "服务器连接连接失败!";}Message msg = new Message();byte[] data = strname.getBytes();msg.obj = data;msg.what = SHOW_OPERINFO;// 显示操作信息mHandler.sendMessage(msg);}}).start();}//启动一个线程,一直读取从服务端发送过来的消息private class ReadThread extends Thread {@Overridepublic void run() {while (true) {try {BufferedInputStream bufferedInput = new BufferedInputStream(msocket.getInputStream());if (bufferedInput.available() > 0) {int len = bufferedInput.available();byte[] data = new byte[len];int nowbyten =bufferedInput.read(data);Message msg = new Message();msg.obj = data;msg.what = CHECK_DATA;// 检查接收到的数据,自动发送验证码mHandler.sendMessage(msg);}}catch (IOException e){}}}}// 维持在线的心跳包class KeepAliveHeartBeat implements Runnable{long checkDelay = 10;long keepAliveDelay = 2000;int iheratBreakErrNum = 0;int iheratBreakNormalNum = 0;public void run() {cKeepAliveblv = true;while(!isconnectBoolean){// wait connect,...try {Thread.sleep(checkDelay);}catch(InterruptedException e){}}while(isconnectBoolean){if(System.currentTimeMillis()-lastSendTime>keepAliveDelay && sendLockblv == false){sendLockblv = true;//try {bos.write("bs60HEARTBEAT".getBytes());//要flush一下bos.flush();iheratBreakErrNum = 0;iheratBreakNormalNum++;} catch (IOException e) {e.printStackTrace();iheratBreakErrNum++;}lastSendTime = System.currentTimeMillis();sendLockblv = false;if(iheratBreakErrNum > 3){break;}}else{try {Thread.sleep(checkDelay);} catch (InterruptedException e) {e.printStackTrace();}}if(iheratBreakNormalNum >= 4){iheratBreakNormalNum = 0;Message msg = new Message();msg.obj = "...";msg.what = SERVER_NORMAL;// 显示网络连接正常的信息mHandler.sendMessage(msg);}}if(iheratBreakErrNum > 3){Message msg = new Message();msg.obj = "Server Break";msg.what = SERVER_BREAK;// 处理服务器中断mHandler.sendMessage(msg);}cKeepAliveblv = false;}}

// 发送SMS
      要从验证手机向其它手机发送手机验证码,需要得到发送SMS权限。此类代码网上比较多,这里就不提供了。

《“透视”个人大数据》项目开发小记 --(二)网络服务端,邮箱验证和手机验证(C#,Java)相关推荐

  1. 大数据项目开发hadoop集群搭建 python爬取前程无忧招聘网信息以及进行数据分析和数据可视化

    大数据项目开发实训报告 一.Hadoop环境搭建 1: jdk的安装 1):在linux系统下的opt目录下创建software 和 module 两个目录 2):利用filezilla工具将 jdk ...

  2. 大数据项目开发实训报告

                                                大数据项目开发实训 一.总体设计               爬取招聘网站前程无忧:               ...

  3. VS2015之博大精深的MFC项目开发(二)

    VS2015之博大精深的MFC项目开发(二) 第二章 MFC原理篇 1.MFC06-1:CString类的测试 1.1 operator+函数 1.2 Delete函数 1.3 Find函数 1.4 ...

  4. 100个vc小项目开发:二、一步一点设计音乐播放器 [I]

    100个vc小项目开发:二.一步一点设计音乐播放器 [源码解读] 文章作者: July 软件来源:开源 ================== 1.有不正之处,恳请指正. 2.本文贴出的是关键实现代码部 ...

  5. 魔坊APP项目-18-种植园,基于支付宝提供的沙箱测试环境开发支付接口、服务端, 处理支付结果的同步通知和异步通知、修复页面底部菜单无法被点击的BUG

    种植园 一.基于支付宝提供的沙箱测试环境开发支付接口 沙箱环境: https://openhome.alipay.com/platform/appDaily.htm?tab=info 开发文档: ht ...

  6. C#开发BIMFACE系列19 服务端API之获取模型数据4:获取多个构件的共同属性

    系列目录     [已更新最新开发文章,点击查看详细] 在前几篇博客中介绍了一个三维文件/模型包含多个构建,每个构建又是由多种材质组成,每个构建都有很多属性.不同的构建也有可能包含相同的属性. 上图中 ...

  7. C#开发BIMFACE系列20 服务端API之获取模型数据5:批量获取构件属性

    系列目录     [已更新最新开发文章,点击查看详细] 在<C#开发BIMFACE系列18 服务端API之获取模型数据3:获取构件属性>中介绍了获取单个文件/模型的单个构建的属性,本篇介绍 ...

  8. C#开发BIMFACE系列18 服务端API之获取模型数据3:获取构件属性

    系列目录     [已更新最新开发文章,点击查看详细] 本篇主要介绍如何获取单文件/模型下单个构建的属性信息. 请求地址:GET https://api.bimface.com/data/v2/fil ...

  9. BaaS让你快速开发APP,和服务端说再见

    作为 移动应用 个人开发者或者小团队, 经常纠结的一个问题就是 我会APP(Android/IOS)开发,但是繁重服务端开发我没有这个能力或者说能力不强,这时你就会思考,有没有公司专门为APP提供服务 ...

最新文章

  1. android 崩溃搜索 AndroidRuntime
  2. SQL:查询学习笔记
  3. EXCEL文件上传与下载
  4. mysql数据库new和old_数据库触发器中new表和old表是什么意思?
  5. SAP CRM系统里Opportunity预期销售金额和货币相关的自动转换
  6. kylinH5框架之项目脚手架
  7. oracle复杂的子查询,Oracle 子查询(复杂select语句)
  8. xlwings复制sheet_Python操作Excel的Xlwings教程(六)
  9. Spring事务方法与非事务方法执行相互调用不回滚,你踩过这个坑没?
  10. 关于FD.io VPP的最新消息
  11. 华容道与数据结构 (续 3)
  12. 第三章 游戏软件工程基础
  13. 曲线拟合最小二乘法对数c语言实现,数值计算_第6章曲线拟合的最小二乘法
  14. SQL server连接数据库
  15. python可视化经纬度信息
  16. Vue实现仿豆瓣电影
  17. js实现轮播图背景色随之渐变的效果(小程序版)
  18. 机器学习中,矩阵转置的求导运算
  19. cpu_scale/max_freq_scale/cpu_capacity/cpu_capacity_orig的含义
  20. Taylor’s Formula - 泰勒公式

热门文章

  1. 六兄弟原来手中各有多少桔子?
  2. 微信小程序开发笔记 进阶篇②——多个微信小程序一个用户体系,同一个UnionID
  3. ImageNet调查报告
  4. 电脑显示你的计算机资源不足怎么办,网络适配器提示系统资源不足解决方法
  5. lbm 弛豫时间_弛豫时间
  6. 游戏服务器端开发要点
  7. 幼儿抽象逻辑思维举例_哈啰思维幼儿数学逻辑思维app下载-哈啰思维幼儿数学逻辑思维手机版 v1.0.1...
  8. adb connect 连不上_使用ADB命令卸载安卓手机系统软件
  9. zsh如何运行conda | zsh anconda | zsh终端下配置aonconda环境 | zsh: command not found: conda
  10. Linux下MQ安装步骤及MQ常用命令