PHP - WAMP 服务器拒绝串行端口(com 端口)访问 (Windows)

PHP - Serial Port (com port) access denied in WAMP server (Windows)

我一直在尝试编写一个 PHP 脚本来通过连接到服务器计算机的 GSM 调制解调器发送 SMS 消息。

下面是上述PHP脚本。

<?php 
$device = "COM7";
exec("mode $device BAUD=9600 PARITY=n DATA=8");
$comport = fopen($device, "w");
fputs($comport,"AT+CMGF=1\n\r");
fputs($comport,"AT+cmgs=\"xxxxxxxxxx\"\n\r");
fputs($comport,"sms text\n\r");
fputs($comport,chr(26));
fclose($comport);
echo "done";  
?>

当我尝试 运行 上述代码时,出现以下错误;

Warning: fopen(COM7): failed to open stream: Permission denied in E:\wamp\www\sms\index.php on line 4

Warning: fclose() expects parameter 1 to be resource, boolean given in E:\wamp\www\sms\index.php on line 9

我已经尝试更改 windows 中的用户权限以允许 WAMP 服务器完全访问,默认情况下 WAMP 服务器已经拥有该权限。

作为解决方法,我尝试使用 DIO 扩展,在尝试打开端口时出现类似的错误。 DIO 还给出了权限被拒绝的错误。

在Whosebug这里建议使用GSM调制解调器的物理地址,而不是"COM7",我试过了没有用。另一个答案建议将 www-data 添加到拨出组,但该解决方案适用于 Linux。

我尝试编写一个 Java servlet 作为解决此问题的方法。 Java 程序 运行 作为独立文件,但是当它的 运行 通过 Tomcat 作为 servlet 时,它再次给出 "Access Violation" 错误。我将 RXTX 库用于 Java servlet。

所以我猜测这个错误是由于没有分配给任何试图通过服务器访问 com 端口的人的权限造成的。 (当我从上面的 PHP 脚本 运行 echo get_current_user(); 时得到 "SYSTEM")

我正在尝试找出此错误的根本原因。非常感谢您的帮助。


下面是使用 RXTX 库的 Java 短信发送器 class。

import java.io.*;
import java.util.*;
import gnu.io.*;

public class SMSsender {
    static Enumeration portList;
    static CommPortIdentifier portId;
    static String messageString1 = "AT";
    static String messageString3 = "AT+CMGF=1";
    static String messageString4 = "AT+CMGS=\"+xxxxxxxxxx\"";

    static String messageString5 = "TESTY2";
    static SerialPort serialPort;
    static OutputStream outputStream;
    static InputStream inputStream;
    static char enter = 13;

    static char CTRLZ = 26;

    public void sendMessage(String[] args) throws InterruptedException {
        portList = CommPortIdentifier.getPortIdentifiers();

        while (portList.hasMoreElements()) {

            portId = (CommPortIdentifier) portList.nextElement();
            if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {

                if (portId.getName().equals("COM7")) {

                    try {
                        serialPort = (SerialPort) portId.open("COM7", 2000);
                    } catch (PortInUseException e) {
                        System.out.println("err");
                    }
                    try {
                        outputStream = serialPort.getOutputStream();
                        inputStream = serialPort.getInputStream();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    try {
                        serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8,

                                SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
                    } catch (UnsupportedCommOperationException e) {
                        e.printStackTrace();
                    }
                    try {

                        outputStream.write((messageString1 + enter).getBytes());

                        Thread.sleep(100);
                        outputStream.flush();

                        // outputStream.write((messageString2 + enter).getBytes());

                        Thread.sleep(100);
                        outputStream.flush();

                        outputStream.write((messageString3 + enter).getBytes());

                        Thread.sleep(100);
                        outputStream.flush();

                        outputStream.write((messageString4 + enter).getBytes());

                        Thread.sleep(100);
                        outputStream.flush();

                        outputStream.write((messageString5 + CTRLZ).getBytes());

                        outputStream.flush();
                        Thread.sleep(100);

                        System.out.println("step 1");
                        Thread.sleep(3000);

                        outputStream.close();
                        serialPort.close();
                        System.out.println("step 2");

                    } catch (IOException e) {
                        e.printStackTrace();
                        serialPort.close();
                    } finally {
                        serialPort.close();
                    }
                }
            }
        }
    }
}

以上代码在 运行 服务器外部作为独立应用程序时有效。

以下是调用上述 class 发送 SMS 的 servlet 代码。

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class sendSMS extends HttpServlet {
       @Override
       public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        // Set the response MIME type of the response message
        response.setContentType("text/html");
        // Allocate a output writer to write the response message into the network socket
        PrintWriter out = response.getWriter();

        SMSsender obj = new SMSsender();
        try {
          obj.sendMessage(null);  
        }
        catch(Exception e)
        {
          out.println(e.getMessage());
        }
        finally {
        out.close();  // Always close the output writer
        }
    }
 }

当此 servlet 运行 通过 Apache Tomcat 时,服务器自动关闭并在日志中显示以下错误。

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000001cf32174465, pid=5828, tid=2276
#
# JRE version: Java(TM) SE Runtime Environment (10.0.2+13) (build 10.0.2+13)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (10.0.2+13, mixed mode, tiered, compressed oops, g1 gc, windows-amd64)
# Problematic frame:
# C  [rxtxSerial.dll+0x4465]
#
# No core dump will be written. Minidumps are not enabled by default on client versions of Windows
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.

我能够解决问题。

显然,windows 不再允许通过虚拟文件名与串行端口通信。在 PHP 的情况下,我试图通过 fopen("com7") 与 com 端口取得联系。因此,这种方法似乎不再可行。这是根据大卫吉布森的说法。 View Source Here。如果我能找到原始来源,我很乐意阅读更多相关内容。

根据 David Gibson 的 post,像 DIO 这样的 PHP 扩展在 Windows 环境中不是很稳定。所以我不再尝试为我的 PHP 代码寻找解决方案。

现在 Java 解决方法

早些时候我尝试使用 RXTX java 库。尽管该代码作为独立应用程序运行,但当通过 tomcat 运行 时,它失败并出现 "Access Violation" 错误。 我想知道 RXTX 是否仍在积极开发中。

无论如何,我已经厌倦了平台无关的解决方案jSerialComm。非常惊人,它不需要任何 DLL 或任何其他本机库。

感谢这个很棒、易于使用的库,我终于能够通过 servlet 发送 SMS。我在下面 post 编辑了我的工作 Java 代码供您参考。

我希望这对面临同样问题的人有所帮助!干杯!

感谢 Mehdi、Erwin 和 Sanguinary 就使用这个令人惊叹的 Whosebug 平台以及开发人员提供的指导!

注意:下面这段代码比较乱,没有优化。此代码仅供参考。

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
//import java.io.InputStream;
import java.util.Scanner;
import com.fazecast.jSerialComm.*;

public class sendSMS extends HttpServlet {
    SerialPort ubxPort;

    static String messageString1 = "AT";
    static String messageString2 = "AT+CMGF=1"; 
    static String messageString3 = "AT+CMGS=\"+xxxxxxxxxx\"";
    static String messageString4 = "TESTY2";
    static char enter = 13;
    static char CTRLZ = 26;


   @Override
   public void doGet(HttpServletRequest request, HttpServletResponse response)
         throws IOException, ServletException {

      // Set the response MIME type of the response message
      response.setContentType("text/html");
      // Allocate a output writer to write the response message into the network socket
      PrintWriter out = response.getWriter();


      try {

          ubxPort = SerialPort.getCommPort("com7");
          boolean openedSuccessfully = ubxPort.openPort();
          out.println("h1<br>");
          if(openedSuccessfully)
          {
            out.println("Port Opened<br>");
            byte[] buffer = (messageString1 + enter).getBytes();
            ubxPort.writeBytes(buffer, buffer.length);
            out.println("1 sent<br>");

            InputStream in = ubxPort.getInputStream();
            try
            {
               for (int j = 0; j < 1000; ++j)
                  System.out.print((char)in.read());
               in.close();
            } catch (Exception e) { e.printStackTrace(); }

            buffer = (messageString2 + enter).getBytes();
            ubxPort.writeBytes(buffer, buffer.length);
            out.println("2 sent<br>");

            try
            {
               for (int j = 0; j < 1000; ++j)
                  System.out.print((char)in.read());
               in.close();
            } catch (Exception e) { e.printStackTrace(); }

            buffer = (messageString3 + enter).getBytes();
            ubxPort.writeBytes(buffer, buffer.length);
            out.println("3 sent<br>");

            try
            {
               for (int j = 0; j < 1000; ++j)
                  System.out.print((char)in.read());
               in.close();
            } catch (Exception e) { e.printStackTrace(); }

            buffer = (messageString4 + CTRLZ).getBytes();
            ubxPort.writeBytes(buffer, buffer.length);
            out.println("4 sent<br>");

            try
            {
               for (int j = 0; j < 1000; ++j)
                  System.out.print((char)in.read());
               in.close();
            } catch (Exception e) { e.printStackTrace(); }

          }

      }
      catch(Exception e)
      {
          out.println("here3");
          out.println(e.getMessage());
      }
      finally {
          ubxPort.closePort();
          out.println("here4");
         out.close();  // Always close the output writer
      }
   }
}