今天写给大家一些干货。场景是这样的:客户需要http的方式对接我们原有的的一个程序,但是我不想每台机器上都部署IIS服务,因为这样会增加部署复杂度和成本。而且也不能保证每个机器都可以部署成功。于是我想换一种方式来应答对方程序的请求。于是有了以下尝试:

图片1

我使用tcp工具建立一个端口为6000的监听服务,再用浏览器访问 http://127.0.0.1:6000这个地址。可以发现tcp工具获得到了浏览起的请求信息。

我们在尝试将访问的地址改为:http://127.0.0.1:6000?para1=123。 可以看到在tcp工具中可以获得到请求的参数信息。如下图:

图片2

经过上面的尝试,我们发现用tcp服务来监听http请求这个方法是可行的,有兴趣的同学可以使用postman这个工具来尝试各种get请求或者post提交请求,来看看tcp服务到底会收到什么样格式的数据。

##那么我们怎么来响应对方的http的请求呢? 假设业务上我们需要给对方返回的http状态有: 成功200、未找到页面或者文件404、服务器内部错误400、无需操作304;在返回类型上需要:普通的文本、本地文件。那么我们只要按照如下格式返回给对方:


  byte[] buffer = new byte[1024];
                    int revCount = client.Available;
                    int revLen = client.Receive(buffer, 0, 1024, SocketFlags.None);
                    DateTime revDateTime = DateTime.UtcNow;
                    if (revLen <= 0)
                    {
                        keepalive = false;
                        netMsg = "Receive Empty String";
                        LogHelper.TcpLog(netMsg);
                        continue;
                    }
                    //将获取到的数据转成字符串
                    string clientRequest = System.Text.Encoding.ASCII.GetString(buffer, 0, revLen);

  if (clientRequest.Contains("login"))
                    {
                        if (clientRequest.Contains("sn=") &&
                            clientRequest.Contains("model=") &&
                            clientRequest.Contains("mac=") &&
                            clientRequest.Contains("ver=") &&
                            clientRequest.Contains("sense=") &&
                            clientRequest.Contains("display="))
                        {
                            try
                            {
                                string sn, model, mac, ver, sense, display, ipaddrs;
                                clientRequest = clientRequest.Substring(clientRequest.IndexOf("sn="));
                                sn = clientRequest.Substring(3, clientRequest.IndexOf('&') - 3);
                                clientRequest = clientRequest.Substring(clientRequest.IndexOf("model="));
                                model = clientRequest.Substring(6, clientRequest.IndexOf('&') - 6);
                                clientRequest = clientRequest.Substring(clientRequest.IndexOf("mac="));
                                mac = clientRequest.Substring(4, clientRequest.IndexOf('&') - 4);
                                clientRequest = clientRequest.Substring(clientRequest.IndexOf("ver="));
                                ver = clientRequest.Substring(4, clientRequest.IndexOf('&') - 4);
                                clientRequest = clientRequest.Substring(clientRequest.IndexOf("sense="));
                                sense = clientRequest.Substring(6, clientRequest.IndexOf('&') - 6);
                                clientRequest = clientRequest.Substring(clientRequest.IndexOf("display="));
                                display = clientRequest.Substring(8, clientRequest.IndexOf(" ") - 8);
                                Console.WriteLine("display++++++++++++++" + display);
                                ipaddrs = ((IPEndPoint)client.RemoteEndPoint).Address.ToString();
 
                                TerminalType = model;
                      
                                string resolution = "";
                                switch (sense)
                                {
                                    case "1":
                                        resolution = "1920*1080";
                                        break;
                                    case "2":
                                        resolution = "1080*1920";
                                        break;
                                    case "3":
                                        resolution = "1366*768";
                                        break;
                                    case "4":
                                        resolution = "768*1366";
                                        break;
                                    case "5":
                                        resolution = "720*1280";
                                        break;
                                    case "6":
                                        resolution = "800*600";
                                        break;
                                    case "7":
                                        resolution = "1024*768";
                                        break;
                                    case "8":
                                        resolution = "1280*768";
                                        break;
                                    case "9":
                                        resolution = "1280*800";
                                        break;
                                    case "10":
                                        resolution = "1280*1024";
                                        break;
                                    case "11":
                                        resolution = "1360*768";
                                        break;
                                    case "12":
                                        resolution = "768*1360";
                                        break;
                                    case "13":
                                        resolution = "1280*720";
                                        break;
                                    case "14":
                                        resolution = "1024*1280";
                                        break;
                                    case "15":
                                        resolution = "2048*1536";
                                        break;
                                    case "16":
                                        resolution = "1536*2048";
                                        break;
                                    case "17":
                                        resolution = "768*1024";
                                        break;
                                    case "18":
                                        resolution = "1600*900";
                                        break;
                                    case "19":
                                        resolution = "900*1600";
                                        break;
                                    case "20":
                                        resolution = "1440*900";
                                        break;
                                    case "21":
                                        resolution = "900*1440";
                                        break;
                                    case "22":
                                        resolution = "1680*1050";
                                        break;
                                    case "23":
                                        resolution = "1050*1680";
                                        break;
                                    default:
                                        resolution = "1920*1080";
                                        break;
                                }
                                // 更新数据库终端信息    
                                TerminalInfo result = SqLiteDataManger.Query<TerminalInfo>(string.Format("select * from tbTerminal where SN = '{0}'", sn)).FirstOrDefault();
                                if (result != null)
                                {
                                    string updateTerminal = string.Format("update tbTerminal set Online={0},IP='{1}',Mac='{2}',Screen='{3}' ,TerminalType='{4}',Version='{5}' where SN='{6}'", 1, (client.RemoteEndPoint as IPEndPoint).Address.ToString(), mac, resolution, TerminalType, ver, sn);
                                    SqLiteDataManger.ExecuteSql(updateTerminal);
                                }
                                else
                                {
                                    string httpHeaderSNNotExistsString = "HTTP/1.1 400 \r\n";
                                    httpHeaderSNNotExistsString += "Server: Apache-Coyote/1.1 \r\n";
                                    httpHeaderSNNotExistsString += "X-Powered-By: Servlet 2.4; JBoss-4.0.5.GA (build: CVSTag=Branch_4_0 date=200610162339)/Tomcat-5.5\r\n";
                                    httpHeaderSNNotExistsString += "Content-Disposition: attachment;filename=" + "PlayList.SCH" + "\r\n";
                                    httpHeaderSNNotExistsString += "Content-Type: text/plain\r\n";
                                    httpHeaderSNNotExistsString += "Content-Length: 0\r\n";
                                    httpHeaderSNNotExistsString += "Date: " + DateTime.Now.ToString("r") + "\r\n";
                                    httpHeaderSNNotExistsString += "Connection: close" + "\r\n";
                                    httpHeaderSNNotExistsString += "\r\n";
                                    byte[] byteSNNotMessage = Encoding.ASCII.GetBytes(httpHeaderSNNotExistsString);
                                    client.Send(byteSNNotMessage);
                                    netMsg = "Terminal Not Exists";
                                    Tools.LogHelper.TcpLog(netMsg);
                                    continue;
                                }

                                string httpHeaderString = "HTTP/1.1 200 OK\r\n";
                                httpHeaderString += "Apache-Coyote/1.1\r\n";
                                httpHeaderString += "Servlet 2.4; JBoss-4.0.5.GA (build: CVSTag=Branch_4_0 date=200610162339)/Tomcat-5.5\r\n";
                                httpHeaderString += "0" + "\r\n";
                                httpHeaderString += "\r\n";
                                byte[] byteMessage = Encoding.ASCII.GetBytes(httpHeaderString);
                                client.Send(byteMessage);
                                netMsg = sn + " 登录成功";
                                Tools.LogHelper.TcpLog(netMsg);
                            }
                            catch (Exception e) // “解析、更新数据库”出错
                            {
                                string httpHeaderString = "HTTP/1.1 400 \r\n";
                                httpHeaderString += "Server: Apache-Coyote/1.1 \r\n";
                                httpHeaderString += "X-Powered-By: Servlet 2.4; JBoss-4.0.5.GA (build: CVSTag=Branch_4_0 date=200610162339)/Tomcat-5.5\r\n";
                                httpHeaderString += "Content-Disposition: attachment;filename=" + "PlayList.SCH" + "\r\n";
                                httpHeaderString += "Content-Type: text/plain\r\n";
                                httpHeaderString += "Content-Length: 0\r\n";
                                httpHeaderString += "Date: " + DateTime.Now.ToString("r") + "\r\n";
                                httpHeaderString += "Connection: close" + "\r\n";
                                httpHeaderString += "\r\n";
                                byte[] byteMessage = Encoding.ASCII.GetBytes(httpHeaderString);
                                client.Send(byteMessage);
                                WriteErrLog("登录出错", e);
                                netMsg = "login failed";
                                Tools.LogHelper.TcpLog(netMsg);
                            }
                        }
                        else // 格式错误
                        {
                            string httpHeaderString = "HTTP/1.1 400 \r\n";
                            httpHeaderString += "Server: Apache-Coyote/1.1 \r\n";
                            httpHeaderString += "X-Powered-By: Servlet 2.4; JBoss-4.0.5.GA (build: CVSTag=Branch_4_0 date=200610162339)/Tomcat-5.5\r\n";
                            httpHeaderString += "Content-Disposition: attachment;filename=" + "PlayList.SCH" + "\r\n";
                            httpHeaderString += "Content-Type: text/plain\r\n";
                            httpHeaderString += "Content-Length: 0\r\n";
                            httpHeaderString += "Date: " + DateTime.Now.ToString("r") + "\r\n";
                            httpHeaderString += "Connection: close" + "\r\n";
                            httpHeaderString += "\r\n";
                            byte[] byteMessage = Encoding.ASCII.GetBytes(httpHeaderString);
                            client.Send(byteMessage);

                            netMsg = "参数格式错误";
                            Tools.LogHelper.TcpLog(netMsg);
                        }
                    }

上面这段代码是客户端的一个http的登录请求,里面包含了登录提交的一些信息,服务端可以用receive()方法将接收到的字节转化为字符串解析。至于需要返回什么样的信息,可以通用实际的业务需要来组装响应的字符串发送给http的客户端。

##延伸 如何给客户端发送文件呢?

发送文件我们需要注意以下几点: 1.在返回的字符串中需要包含文件的大小信息。 2.必选先发送文本头信息,再发送文件。

为什么需要注意上面两点呢。因为tcp是传输层的协议,能传输字节流,保证流的顺序,但不明确每次请求应答的流的大小;而http是应用层协议,是包含数据包格式的。所以我们用tcp响应的时候需要遵守http协议的格式来发送数据流。 下面是给http客户端传送文件的代码:

 // 如果文件存在则发送
                                if (filePath != null && fileSig != null && File.Exists(filePath))
                                {
                                    netMsg = string.Format("{0} {1} {2}", sn, "StartDownload", filePath);
                                    //MainForm.m_Logger.Log(Level.Info, netMsg);
                                    Console.WriteLine(string.Format("{0} {1}", filePath, "Start"));
                                    FileInfo fi = new FileInfo(filePath);
                                    string httpHeaderString = "HTTP/1.1 200 OK\r\n";
                                    httpHeaderString += "Server: Apache-Coyote/1.1\r\n";
                                    httpHeaderString += "X-Powered-By: Servlet 2.4; JBoss-4.0.5.GA (build: CVSTag=Branch_4_0 date=200610162339)/Tomcat-5.5\r\n";
                                    httpHeaderString += "Content-Disposition:attachment;filename=" + fileSig + "\r\n";
                                    httpHeaderString += "Last-modified: " + fi.LastWriteTime.ToString("r") + "\r\n";
                                    httpHeaderString += "Content-Type:text/plain\r\n";
                                    if (clientRange != "" && clientRange != "0")
                                    {
                                        int startPos = Convert.ToInt32(clientRange);
                                        FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                                        BinaryReader br = new BinaryReader(fs);
                                        br.BaseStream.Position = startPos;
                                        httpHeaderString += "Content-Length:" + (fi.Length - startPos).ToString() + "\r\n";
                                        httpHeaderString += "Date: " + DateTime.Now.ToString("r") + "\r\n";
                                        httpHeaderString += "Connection: close" + "\r\n";
                                        httpHeaderString += "\r\n";

                                        Byte[] bufferSend = new Byte[1024];
                                        int num = 0;
                                        while ((num = br.Read(bufferSend, 0, bufferSend.Length)) != 0)
                                        {
                                            client.Send(bufferSend, num, SocketFlags.None); 
                                        }

                                        netMsg += "断点续传:" + startPos;
                                        netMsg = string.Format(" {0} {1} {2}", sn, "EndDownload", filePath); 
                                        Tools.LogHelper.TcpLog(netMsg);
                                    }
                                    else
                                    {
                                        httpHeaderString += "Content-Length:" + fi.Length.ToString() + "\r\n";
                                        httpHeaderString += "Date: " + DateTime.Now.ToString("r") + "\r\n";
                                        httpHeaderString += "Connection: close" + "\r\n";
                                        httpHeaderString += "\r\n";
                                        byte[] byteMessage = Encoding.ASCII.GetBytes(httpHeaderString);
                                        client.Send(byteMessage);
                                        client.SendFile(filePath);



                                        TerminalInfo terminalInfo = Sqlite.SqLiteDataManger.Query<TerminalInfo>(string.Format("select * from tbTerminal where SN='{0}'", sn)).FirstOrDefault();
                                        //terminalInfo.Status = 6; 
                                        Sqlite.SqLiteDataManger.ExecuteSql(string.Format("update tbTerminal set DownMediaCount={0},Status={1} where SN='{2}'", ++terminalInfo.DownMediaCount, terminalInfo.Status, terminalInfo.SN));


                                        //即使更新页面数据
                                        Messenger.Default.Send(terminalInfo, MessageToken.UpdateTerminalDownloadNum);

                                        netMsg = string.Format("{0} {1} {2}", sn, "EndDownload", filePath);
                                        Tools.LogHelper.TcpLog(netMsg);
                                    }

                                    Sqlite.SqLiteDataManger.ExecuteSql(string.Format("update tbMedia set RefCount={0} where FID='{1}'", mediaInfo.RefCount - 1, fid));


                                }
                                else // “串号/文件”不存在
                                {
                                    string bodyStr = "Http Status 404 Media File Not Found";
                                    string httpHeaderString = "HTTP/1.1 404 \r\n";
                                    httpHeaderString += "Server: Apache-Coyote/1.1 \r\n";
                                    httpHeaderString += "X-Powered-By: Servlet 2.4; JBoss-4.0.5.GA (build: CVSTag=Branch_4_0 date=200610162339)/Tomcat-5.5\r\n";
                                    httpHeaderString += "Content-Disposition: attachment;filename=" + "PlayList.SCH" + "\r\n";
                                    httpHeaderString += "Content-Type: text/plain\r\n";
                                    httpHeaderString += "Content-Length: " + bodyStr.Length.ToString() + "\r\n";
                                    httpHeaderString += "Date: " + DateTime.Now.ToString("r") + "\r\n";
                                    httpHeaderString += "Connection: close" + "\r\n";
                                    httpHeaderString += "\r\n";
                                    httpHeaderString += bodyStr;
                                    byte[] byteMessage = Encoding.ASCII.GetBytes(httpHeaderString);
                                    client.Send(byteMessage);

                                    netMsg = string.Format("{0} {1} {2} {3}", sn, fid, filePath, "fid/文件不存在");
                                    Tools.LogHelper.TcpLog(netMsg);
                                }
                            }
                            catch (Exception e) // “解析/查表/发送文件”出错
                            {
                                string httpHeaderString = "HTTP/1.1 400 \r\n";
                                httpHeaderString += "Server: Apache-Coyote/1.1 \r\n";
                                httpHeaderString += "X-Powered-By: Servlet 2.4; JBoss-4.0.5.GA (build: CVSTag=Branch_4_0 date=200610162339)/Tomcat-5.5\r\n";
                                httpHeaderString += "Content-Disposition: attachment;filename=" + "PlayList.SCH" + "\r\n";
                                httpHeaderString += "Content-Type: text/plain\r\n";
                                httpHeaderString += "Content-Length: 0\r\n";
                                httpHeaderString += "Date: " + DateTime.Now.ToString("r") + "\r\n";
                                httpHeaderString += "Connection: close" + "\r\n";
                                httpHeaderString += "\r\n";
                                byte[] byteMessage = Encoding.ASCII.GetBytes(httpHeaderString);
                                client.Send(byteMessage);

                                Tools.LogHelper.ErrorLog(e);
                                Tools.LogHelper.TcpLog("发送素材异常 " + e.Message);
                            }
                        }
                        else // 格式错误
                        {
                            string httpHeaderString = "HTTP/1.1 400 \r\n";
                            httpHeaderString += "Server: Apache-Coyote/1.1 \r\n";
                            httpHeaderString += "X-Powered-By: Servlet 2.4; JBoss-4.0.5.GA (build: CVSTag=Branch_4_0 date=200610162339)/Tomcat-5.5\r\n";
                            httpHeaderString += "Content-Disposition: attachment;filename=" + "PlayList.SCH" + "\r\n";
                            httpHeaderString += "Content-Type: text/plain\r\n";
                            httpHeaderString += "Content-Length: 0\r\n";
                            httpHeaderString += "Date: " + DateTime.Now.ToString("r") + "\r\n";
                            httpHeaderString += "Connection: close" + "\r\n";
                            httpHeaderString += "\r\n";
                            byte[] byteMessage = Encoding.ASCII.GetBytes(httpHeaderString);
                            client.Send(byteMessage);

                            Tools.LogHelper.TcpLog("请求素材格式错误");
                        }

通过上面的代码可以看出 ,需要先得到文件大小信息放置在响应的头中 httpHeaderString += "Content-Length: " + bodyStr.Length.ToString() + "\r\n";;在发送文件,发送文件可以使用 client.SendFile(filePath);;其中client为socket对象,sendfile()为内置方法,可以异步发送文件,但无法监控进度。