精华内容
下载资源
问答
  • 插口

    2014-10-26 11:50:27
    插口层的主要功能是将进程发送的与协议有关的请求映射到产生插口时指定的与协议有关的实现。下图说明了进程中的插口 接口与内核中的协议实现之间的层次关系。 1.socket结构 插口代表一条通信链路...

    插口层的主要功能是将进程发送的与协议有关的请求映射到产生插口时指定的与协议有关的实现。下图说明了进程中的插口

    接口与内核中的协议实现之间的层次关系。



    1.socket结构

    插口代表一条通信链路的一端,存储或指向与链路有关的所有信息。这些信息包括:使用的协议、协议的状态信息(包括

    源和目的地址)、到达的链接队列、数据缓存和可选标志。下图给出了插口和与插口相关的缓存的定义。


    so_type由产生插口的进程指定,指明插口和相关协议支持的通信语义。对于UDP,为SOCK_DGRAM,对于TCP,为

    SOCK_STREAM。

    so_options是一组改变插口行为的标志。如下图所示:


    通过getsockopt和setsockopt系统调用进程能修改除SO_ACCEPTCONN外所有的插口选项。当在插口上发送listen系统调用

    时,该选项被内核设置。

    so_linger等于当关闭一条连接时插口继续发送数据的时间间隔(单位为一个时钟滴答)

    so_state表示插口的内部状态和一些其他的特点。下图是so_state可能的取值。


    进程可以通过fcntl和ioctl系统调用直接修改SS_ASYNC和SS_NBIO。

    如果设置了SS_NBIO,在对插口执行IO操作且请求的资源不能得到时,内核并不阻塞进程,而是返回EWOULDBLOCK。

    如果设置了SS_ASYNC,当因为下列情况之一而使插口状态发生变化时,内核发送SIGIO信号给so_pgid标识的进程或进程组:

    • 连接请求已完成
    • 断连请求已被启动
    • 断连请求已完成
    • 连接的一个通道已被关闭
    • 插口上有数据到达
    • 数据已被发送
    • UDP或TCP插口上出现了一个一步差错
    so_pcb指向协议控制块,协议控制块包含于协议有关的状态信息和插口参数。每一种协议都定义了自己的控制块结构。所以
    so_pcb被定义成一个通用的指针。下图列出了我们讨论的控制块结构。

    so_proto指向进程在socket系统调用中选择的协议的protosw结构。
    设置了SO_ACCEPTCONN标志的插口维护两个连接队列。还没有完全建立的连接(如TCP的三次握手还没完成)被放在队列
    so_q0中。已经建立的连接或将被接收的连接(TCP的三次握手已完成)被放入队列so_q中。队列的长度分别为so_q0len和
    so_qlen。每一个被排队的连接由它自己的插口来表示。在一个被排队的插口中,so_head指向设置了SO_ACCEPTCONN的
    源插口。
    插口上可排队的连接数通过so_qlimit来控制,进程可以通过listen系统调用来设置so_qlimit。
    下图说明了有三个连接将被接受、一个连接已被建立的情况下的队列内容。

    so_timeo用作accept、connet和close处理期间的等待通道。
    so_error保存差错代码,直到在引用该插口的下一个系统调用期间差错代码能送给进程。
    so_oobmark标识在输入数据流中最近收到的带外数据的开始点。
    每一个插口包含两个数据缓存,so_rcv和so_snd,分别用来缓存接收或发送的数据。
    在Net/3中不使用so_tpcb。so_upcall和so_upcallarg也仅用于Net/3中的NFS软件。

    2.系统调用

    进程同内核交互是通过一组定义好的函数来进行的。这些函数称为系统调用。
    从进程到内核中的受保护的环境的转换是与机器和实现相关的。下面的讨论,我们使用Net/3在386上的实现来说明如何实现
    有关操作。
    在BSD的内核中,每一个系统调用均被编号,当进程执行一个系统调用时,硬件被配置成仅传送控制给一个内核函数。将标识
    系统调用的整数作为参数传给该内核函数。在386实现中,这个内核函数为syscall。利用系统调用的编号,syscall在表中找到
    请求的系统调用sysent结构。表中的每一个单元均为一个sysent结构。
    struct sysent {
    int sy_narg; /* number of arguments */
    int (*sy_call) (); /* implementing function */
    }; /* system call table entry */
    表的形态如下图所示:
    struct sysent sysent[] = {
    /*. . . */
    { 3, recvmsg }, /* 27 = recvmsg */
    { 3, sendmsg }, /* 28 = sendmsg */
    { 6, recvfrom }, /* 29 = recvfrom */
    {3, accept }, /* 30 = accept */
    {3, getpeername }, /* 31=getpeername */
    {3, getsockname }, /* 32 = getsockname */
    /* . . . */
    }
    syscall将参数从调用进程复制到内核中,并且分配一个数组来保存系统调用的结果。然后,当系统调用执行完成后,syscall
    将结果返回给进程。
    syscall将控制交给与系统调用相对应的内核函数。在386实现中,调用有点像:
    struct sysent *callp;
    error = (*callp->sy_call) (p, args, rval);
    这里指针callp指向相关的sysent结构,指针p则指向系统调用的进程的进程表项;args作为参数传给系统调用,它是一个32bit
    长的字数组,而rval则是一个用来保存系统调用的返回结果的数组,数组有两个元素,每个元素是一个32bit长的字。当我们用
    系统调用这个词时,我们指的是被syscall调用的内核中的函数,而不是应用调用的进程中的函数。
    syscall期望系统调用函数在没有差错时返回0,否则返回非0的差错代码。如果没有差错出现,内核将rval中的值作为系统调用
    的返回值传给进程。如果有差错,syscall忽略rval中的值,并以与机器相关的方式返回差错代码给进程,使得进程能从外部变量
    errno中得到差错代码。应用调用的函数则返回-1或一个空指针表示应用应该查看errno获得差错信息。

    2.1.举例

    socket系统调用的原型是:
    int socket(int domain, int type, int protocol);
    实现socket系统调用的内核函数的原型是:
    struct socket_args {
    int domain;
    int type;
    int protocol;
    };
    socket(struct proc *p, struct socket_args *uap, int *retval);
    当一个应用调用socket时,进程用系统调用机制将三个独立的整数传给内核。syscall将参数复制到32bit值的数组中,并将数
    组指针作为第二个参数传给socket的内核版。内核版的socket将第二个参数作为指向socket_args结构的指针。下图显示了
    上述的过程。

    同socket类似,每一个实现系统调用的内核函数将args说明成一个与系统调用有关的结构指针,而不是一个指向32bit的字
    的数组的指针。

    3.网络系统调用

    下图显示了网络系统调用的流程图。


    4.进程、描述符和插口

    本节介绍进程、描述符和插口的数据结构。下图给出了这些结构以及有关的结构成员。

    实现系统调用的函数的第一个参数总是p,即指向调用进程的proc结构的指针。内核利用proc结构记录进程的有关信息。

    在proc结构中,p_fd指向filedesc结构,该结构的主要功能是管理fd_ofiles指向的描述表。描述符表的大小是动态变化的,

    由一个指向file结构的指针数组组成。每一个file结构描述一个打开的文件,该结构可被多个进程共享。

    file结构中,有两个结构成员我们是感兴趣的,f_ops和f_data。I/O系统调用的实现因描述符的I/O对象类型不同而不同。

    f_ops指向fileops结构,该结构包含一张实现read、write、ioctl、select和close系统调用的函数指针表。

    f_data指向相关I/O对象的专用数据,对于插口而言,f_data指向与描述符相关的socket结构。最后,socket结构中的

    so_proto指向产生插口时选中的协议的protosw结构。


    5.socket系统调用

    socket系统调用产生一个新的插口,并将插口同进程在参数domain、type和protocol中指定的协议联系起来。该函数分配

    一个新的描述符,用来在后续的系统调用中标识插口,并将描述符返回给进程。

    系统调用的申明如下:


    函数的大概处理如下:

    1.falloc分配一个新的file结构和fd_ofiles数组中的一个元素,设置file结构的类型,可读、可写并且作为一个插口。

    2.调用socreate分配并初始化一个socket结构。


    5.1.socreate函数

    大多数插口系统调用至少被分成两个函数,与socket和socreate类似,第一个函数从进程哪里获取需要的书序,调用第二个

    函数soxxx来完成功能处理,然后返回结果给进程。这种分成多个函数的做法是为了第二个函数能直接被基于内核的网络协议

    调用。

    socreate函数的大概处理流程如下:

    1.发现协议交换表。根据函数参数查找匹配协议的protosw结构的指针或空指针。

    2.分配并初始化socket结果。分配一个新的socket结构,初始化相关字段。

    3.PRU_ATTACH请求。每一个协议均提供了一个函数来处理从插口层来的通信请求。so->so_proto->pr_usrreq是一个指向

    与插口so相关联协议的用户请求函数指针,函数原型是:

    int pr_usrreq(struct socket *so, int req, struct mbuf *mo, *m1, *m2);

    req是一个标识请求的常数。后三个参数因请求不同而异。下图列出了pr_usrreq函数提供的通信请求。


    4.退出处理。返回新建的socket。


    6.getsock和sockargs函数

    这两个函数重复出现了插口系统调用中。

    getsock的功能是将描述符映射到一个文件表项中。

    sockargs将进程传入的参数复制到内核中的一个新分配mbuf中。


    7.bind系统调用

    bind系统调用将一个本地的网络运输层地址和插口联系起来。一般来说,作为客户的进程并不关心它的本地地址是什么。

    在这种情况下,进程在进行通信之前没有必要调用bind;内核会自动为其选择一个本地地址。

    服务器进程则总是需要绑定到一个已知的地址上。所以进程在接收连接或者接收数据报之前必须调用bind,因为客户进程

    需要同已知的地址建立连接或发送数据报到已知地址。bind系统调用的申明如下:


    bind函数的大概处理如下:

    1.getsock返回描述符的file结构

    2.sockargs将本地地址复制到内核的mbuf中

    3.将file结构和mbuf传给sobind函数。


    7.1.sobind函数

    sobind是一个封装器,它给与插口相关联的协议发送PRU_BIND请求(调用so->so_proto->pr_usrreq函数)。


    8.listen系统调用

    listen系统调用的功能是通知协议进程准备接收插口上的连接请求。它同时也指定插口上可以排队等待的连接数的门限值。

    超过门限值时,插口层将拒绝进入连接请求排队等待。当这种情况出现时,TCP将忽略进入的连接请求。进程可以通过

    调用accept来得到队列中的连接。

    listen系统调用的申明如下:


    listen系统调用的大概处理如下:

    1.调用getsock返回描述符的file结构。

    2.调用solisten将请求传递给协议层。


    8.1.solisten函数

    solisten函数发送PRU_LISTEN请求(调用so->so_proto->pr_usrreq函数),并使插口准备接收连接。


    9.tsleep和wakeup函数

    当一个在内核中执行的进程因为得不到内核资源而不能继续执行时,它就调用tsleep等待。tsleep的原型是:

    int tsleep(caddr_t chan, int pri, char *mesg, int timeo);

    chan称之为等待通道,它标志进程等待的特定资源或事件。许多进程能同时在同一个等待通道上睡眠。当资源可用或事件出

    现时,内核调用wakeup,并将等待通道作为唯一的参数传入。wakeup的原型是:

    void wakeup(caddr_t chan);

    所有等待在该通道上的进程均被唤醒,并被设置成运行状态。当每一个进程恢复执行时,内核安排tsleep返回。下图列出了

    tsleep的返回值。


    因为所有等待在同一个等待通道上的进程均被wakeup唤醒,所有我们总是看到在一个循环中调用tsleep。每一个被唤醒的进程

    在继续执行之前必须检查等待的资源是否可得到,因为另一个被唤醒的进程可能已经先一步得到了资源。如果仍然得不到资源,

    进程再调用tsleep等待。


    10.accept系统调用

    调用listen后,进程调用accept等待连接请求。accept返回一个新的描述符,指向一个连接到客户的新的插口。原来的插口

    仍然是未连接的,并准备接收下一个连接。如果name指向一个正确的缓存,accept就会返回对方的地址。

    处理连接的系统由插口相关联的协议来完成。对于TCP,当一条连接已经被建立(即三次握手已经完成)时,就通知插口层。

    accept系统调用的申明如下:


    函数的大概处理流程如下:

    1.验证参数。

    2.等待连接。while循环中调用tsleep函数。当出现下列情况时,while退出:有一条连接到达;出现差错;插口不能再接收

    数据。在循环内,进程在tsleep中等待,当有连接到达时,tsleep返回0。如果tsleep被信号中断或插口被设置成非阻塞,

    则accept返回EINTR或EWOULDBOLCK。

    3.异步差错。如果进程在睡眠期间出现差错,则将插口中的差错代码赋给accept中的返回码,清除插口中的差错码后,accept

    返回。所以插口必须在每次被唤醒后检查返回值,查看是否在进程睡眠期间有差错出现。

    4.将插口同描述符相关联。falloc函数为新的连接分配一个描述符,将插口从接受队列中删除,放到描述符的fle结构中。

    5.协议处理。调用soaccept来完成协议处理。最后调用copyout将地址拷贝到进程空间。


    10.1.soaccept函数

    soaccept函数确保与一个描述符相连,并发送PRU_ACCEPT请求给协议,pr_surreq返回后,包含了外部插口的名字。


    11.sonewconn和soisconnected函数

    accept等待协议层处理进入的连接请求,并且将它们放入so_q中。下图利用TCP来说明这个过程。


    accept调用tsleep等待进入的连接。tcp_input调用sonewconn为新的连接产生一个插口来处理进入的TCP SYN。sonewconn

    将产生的插口放入so_q0排队,因为三次握手还没有完成。‘

    当TCP握手协议的最后一个ACK到达时,tcp_input调用soisconnected来更新产生的插口,并将它从so_q0中移到so_q中,

    唤醒所有调用accept等待进入的连接的进程。

    当tsleep返回时,accept从so_q中得到连接,发送PRU_ATTACH请求。插口同一个新的文件描述符建立联系,accept也

    返回到调用进程。


    12.connect系统调用

    服务器进程调用listen和accept系统调用等待进程初始化连接。如果进程想自己初始化一条连接(即客户端),则调用connect。

    对于面向连接的协议如TCP,connect建立一条与指定外部地址的连接。如果进程没有调用bind来绑定地址,则内核选择

    并且隐式地绑定一个地址到插口。

    对于无连接协议如UDP或ICMP,connect记录外部地址,以便发送数据报时使用。任何以前的外部地址均被新的地址所代替。

    下图显示了UDP或TCP调用connect时涉及到的函数。


    左边说明connect如何处理无连接协议,如UDP。在这种情况下,协议层调用soisconnected后connect系统调用后立即返回。

    右边说明connect如何处理面向连接的协议,如TCP。在这种情况下,协议层开始建立连接,调用soisconnecting指示连接

    将在某个时候完成。如果插口是非阻塞的,soconnect调用tsleep等待连接完成。对于TCP,当三次握手完成时,协议层调用

    soisconnected将插口标识为已连接。然后调用wakeup唤醒等待的进程,从而完成connect系统调用。

    connect系统调用的申明如下:


    connect系统调用的大概处理流程如下:

    1.开始连接处理。连接是从调用soconnect开始的。

    2.等待连接建立。while循环直到连接已建立或出现差错时才退出。

    3.清楚“正在连接中”的标志,因为连接已经完成或连接请求已失败。释放存储外部地址的mbuf。


    12.1.soconnect函数

    soconnect函数确保插口处于正确的连接状态。如果插口没有连接或连接没有被挂起,则连接请求总是正确的。如果插口

    已经连接或正等待处理,则新的连接请求将被面向连接的协议(如TCP)拒绝。对于无连接协议,如UDP,多个连接是

    允许的,但是每一个新的请求中的外部地址会取代原来的外部地址。

    soconnect发出RPU_CONNECT请求启动相应的协议处理来建立连接或关联。


    13.shutdown系统调用

    shutdown系统调用关闭连接的读通道、写通道或读写通道。对于读通道,shutdown丢弃所有进程还没有读写的数据以及

    调用shutdown之后到达的数据。对于写通道,shutdown使协议作相应的处理。对于TCP,所有剩余的数据将被发送,发送

    完成后发送FIN。这就是TCP的半关闭特点。

    为了删除插口和释放描述符,必须调用close。可以在没有调用shutdown的情况下,直接调用close。同所有描述符一样,

    当进程结束时,内核将调用close,关闭所有还没有被关闭的插口。

    shutdown系统调用的申明如下:


    其中how和how++的期望值如下:


    shutdown是函数soshutdown的包装函数(wrapper function)。由getsock返回与描述符相关联的插口,调用soshutdown,

    并返回其值。

    关闭连接的读通道是由插口层调用sorflush处理的,写通道的关闭是由协议层的PRU_SHUTDOWN请求处理的。


    14.close系统调用

    close系统调用能用来关闭各类描述符,当fd是引用对象的最后的描述符时,与对象有关的close函数被调用:

    error = (*fp->f_ops->fo_close)(fp,p);

    插口的fp->f_ops->fo_close是soo_close函数。

    soo_close函数是soclose函数的封装器,soclose函数取消插口上所有未完成的连接(即,还没有完全被进程接受的连接),

    等待数据被传输到外部系统,释放不需要的数据结构。

    soclose函数的大概处理流程如下:

    1.丢弃未完成的连接。遍历so_q0和so_q两个连接队列,调用soabort函数取消每一个挂起的连接。soabort发送PRU_ABORT

    请求给协议,并返回结果。

    2.断开已建立的连接或关联。如果插口同外部地址相连接,必须断开插口与对等地址之间的连接。

    3.释放数据结构。如果插口仍然同协议相连,则发送PRU_DETACH请求断开插口与协议的联系。最后,插口被标识为同任何

    描述符没有关联,调用sofree函数释放插口。

    展开全文
  • Manhunt:Manhunt插口插件
  • 最近写资料用到按照USB顺序显示所有的USB设备(设备不用按照插入顺序,只需要插入对应USB插口即可),搜了很多资料没有找到想要的实现方式,便自己动手写了一些库文件(结合USB View以及WindowsAPI函数),并且成功移植...

      最近写资料用到按照USB顺序显示所有的USB设备(设备不用按照插入顺序,只需要插入对应USB插口即可),搜了很多资料没有找到想要的实现方式,便自己动手写了一些库文件(结合USB View以及WindowsAPI函数),并且成功移植到MFC工程(我使用的是VS2010工具)。

      首先看下USB View软件显示效果:
    这里写图片描述

        我们看到USB View软件是以树结构显示了USB所有的插口(包括以及连接设备的插口和还未连接设备的插口),但是连接的设备信息却不齐全(比如如何判断是安卓设备以及设备的容器ID和名称等)。

        插入设备的数据采用WindowsAPI函数(WindowsAPI函数的缺点是只能查询到已经连接的设备信息,却不能确定设备信息对应的插口),对于这块我也纠结不少时间…

        后来进行猜想,采用USB View作为USB插口的遍历,然后结合算法把遍历到的数据进行配对,可以组成完成的USB数据信息。

      下面是我的实验计划:
        1.使用USB View函数库进行遍历并且保存所有的USB插口信息(保存已经插入和未插入的),其中树结构分为三级保存,第一级做为主要设备信息(USBHostControllers 主控制器),第二级做为hub设备信息(可以清楚知道hub下有几个USB插口),第三级做为当前hub下的USB插口信息。当然这只是USB View实现的功能;

        2.使用WindowsAPI遍历到所有的USB信息(其中包括Hub信息);

        3.根据USB View插口内的idVendor和idProduct信息进行匹配WindowAPI内所有相关的数据,配对成功后得到容器ID进行遍历剩下的设备信息确保设备信息的完整性以及不重复性,在匹配的过程中我们就可以到插入设备的名称,以及设备类型比如“Android”等,匹配成功后按照USB插口的顺序进行保存顺序(这里只按照计数的形式向后增加USB插口,不再使用树结构);

        4.由于USB View使用C语言写的库文件,需要把一些不兼容MFC的部分进行修改,比如隐藏USB View自带的树结构视图等。


      下面说下使用这个MFC工程的方式:

        首先下载WinDDK 7600.16385.1工具包,这个网上很多下载后,安装到默认的路径:C:\WinDDK; 安装完成后需要把使用的VS2010文件夹路径下的 VC\ include内的所有文件 拷贝覆盖到C:\WinDDK\7600.16385.1\inc\api 文件夹内;

        MFC工程下载地址:https://download.csdn.net/download/a29562268/10294175!

      这个工程可以直接使用,也可以移植内部的文件用来使用,由于修改的文件比较多,只贴出具体实现的文件:

      .h文件

    /*
    *李坤昱
    *QQ:326087275@qq.com
    */
    #include <stdio.h>
    #include <vector>
    #include "usbioctl.h "
    
    
    //枚举出所有的设备信息,然后与USB view信息合并
    struct  List_all_USB_devices 
    {
    	//设备类型 比如USB
    	CString szDeviceInstanceID;
    	//
    	CString Device_Description;
    	//设备描述
    	CString szDesc;
    	//
    	CString Hardware_IDs;
    	//
    	CString pszId;
    	//
    	CString Bus_Reported_Device_Description;
    	//
    	CString Device_Manufacturer;
    	//
    	CString Device_Friendly_Name;
    	//
    	CString Device_Location_Info;
    	//
    	CString Device_Security_Descriptor_String;
    	//容器ID
    	CString ContainerId;
    	//
    	CString Device_Display_Category;
    	//
    	CString pszToken;
    	//vid
    	CString szVid;
    	//pid
    	CString szPid;
    	//mi
    	CString szMi;
    	//如果当前这条数据已经写入设备结构,标记为1 不再进行匹配
    	bool bIs;
    
    	List_all_USB_devices():bIs(0)
    	{
    
    	}
    };
    
    
    struct Usb_List_Data 
    {
    	Usb_List_Data();
    	//获取所有的USB设备信息
    	bool GetAllUsbInfo(std::vector<List_all_USB_devices> & usb_Info);
    private:
    	//保存所有的USB信息
    	std::vector<List_all_USB_devices> Usb_Devices;
    private:
    	//遍历USB设备
    	void ListDevices (CONST GUID *pClassGuid, LPCTSTR pszEnumerator);
    };
    
    typedef struct _STRING_DESCRIPTOR_NODE_
    {
        struct _STRING_DESCRIPTOR_NODE *Next;
        UCHAR                           DescriptorIndex;
        USHORT                          LanguageID;
        USB_STRING_DESCRIPTOR           StringDescriptor[0];
    } STRING_DESCRIPTOR_NODE_, *PSTRING_DESCRIPTOR_NODE_;
    
    
    //
    struct Usb_Info
    {
    	int Count;
    	//
    	int deviceNameSize;
    	//
    	BOOLEAN LowSpeed;
    	//
    	BOOLEAN DeviceIsHub;
    	//
    	USHORT DeviceAddress;
    	//
    	USB_CONNECTION_STATUS ConnectionStatus;
    	//
    	USHORT NumberOfOpenPipes;
    	//
    	PSTRING_DESCRIPTOR_NODE_             stringDescs;
    	//
    	PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfoEx;
    	//
    	PUSB_DESCRIPTOR_REQUEST             configDesc;
    	//
    	CString leafName;
    	//
    	CString driverKeyName;
    	//
    	CString deviceDesc;
    };
    
    //Hub
    struct RootHub
    {
    	int Count;
    	//
    	int DeviceInfoType;
    	//
    	CString HubName;
    	//
    	int deviceNameSize;
    	//
    	CString deviceName;
    	//
    	CString leafName;
    	//
    	PUSB_NODE_INFORMATION   hubInfo;
    	//
    	PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfo;
    	//
    	PUSB_DESCRIPTOR_REQUEST ConfigDesc;
    	//
    	PSTRING_DESCRIPTOR_NODE_ StringDescs;
    
    	std::vector<Usb_Info> Usb;
    };
    //主机控制器
    struct HostControllers
    {
    	//标记当前是第几个主机控制器
    	int Count;
    	//
    	CString DeviceInfoType;
    	//
    	CString DriverKeyName;
    	//
    	CString DeviceId;
    	//
    	ULONG VendorID;
    	//
    	ULONG DeviceID;
    	//
    	ULONG SubSysID;
    	//
    	ULONG Revision;
    	//
    	CString rootHubName;
    	//
    	CString deviceDesc;
    
    	std::vector<RootHub> Hub;
    };
    
    //获取计算机内树形结构形式 所有的USB相关信息,以及先后顺序(用来记录USB设备的位置)
    struct Usb_Id
    {
    	bool GetAllUsbPlace(std::vector<HostControllers> & usb_host);
    public:
    	
    	//设备连接数
    	ULONG devicesConnected;
    private:
    	void GetAllUsbPlace_();
    };
    
    struct Usb_Port
    {
    	//标记是第几个USB插口
    	int nCount;
    	//
    	ULONG VendorID;
    	//
    	ULONG ProductID;
    	//
    	CString Device_Description;
    	//用来保存安卓设备名称
    	CString Device_Description1;
    	//
    	CString Bus_Reported_Device_Description;
    	//
    	CString Device_Manufacturer;
    	//
    	CString Device_Location_Info;
    	//
    	CString ContainerId;
    	//vid
    	CString szVid;
    	//pid
    	CString szPid;
    	//mi
    	CString szMi;
    	//
    	USB_CONNECTION_STATUS ConnectionStatus;
    };
    
    //按循序整理出从Usb插口1开始,一直到最后的设备
    struct Usb_SequenceInfo
    {
    	Usb_List_Data usb_list;
    	Usb_Id Usb_id;
    	bool GetUsbAllPorts(std::vector<Usb_Port> & port);
    private:
    	std::vector<Usb_Port> m_port;
    private:
    	void GetUsbPortsInfo();
    	void WriteUsbPortsInfo(std::vector<List_all_USB_devices> usb_data,std::vector<HostControllers> usb_host);
    };
    

      .cpp文件

    /*
    *李坤昱
    *QQ:326087275@qq.com
    */
    #include "StdAfx.h"
    #include "Usb_.h"
    
    #include "inc/usbview.h"
    #include <windowsx.h>
    
    
    #include <windows.h>  
    #include <devguid.h>    // for GUID_DEVCLASS_CDROM etc  
    #include <setupapi.h>  
    #include <cfgmgr32.h>   // for MAX_DEVICE_ID_LEN, CM_Get_Parent and CM_Get_Device_ID  
    #define INITGUID  
    #include <tchar.h>  
    #include "C:\WinDDK\7600.16385.1\inc\api\devpkey.h" 
    
    #pragma comment (lib, "setupapi.lib") 
    
    
    typedef BOOL (WINAPI *FN_SetupDiGetDevicePropertyW)(  
    	__in       HDEVINFO DeviceInfoSet,  
    	__in       PSP_DEVINFO_DATA DeviceInfoData,  
    	__in       const DEVPROPKEY *PropertyKey,  
    	__out      DEVPROPTYPE *PropertyType,  
    	__out_opt  PBYTE PropertyBuffer,  
    	__in       DWORD PropertyBufferSize,  
    	__out_opt  PDWORD RequiredSize,  
    	__in       DWORD Flags  
    	);  
    
    char *strupr(char *str);
    
    #define ARRAY_SIZE(arr)     (sizeof(arr)/sizeof(arr[0]))  
    
    Usb_List_Data::Usb_List_Data()
    {
    
    }
    
    // 获取所有的USB信息
    void Usb_List_Data::ListDevices (CONST GUID *pClassGuid, LPCTSTR pszEnumerator)  
    {  
    	unsigned i, j;  
    	DWORD dwSize, dwPropertyRegDataType;  
    	DEVPROPTYPE ulPropertyType;  
    	CONFIGRET status;  
    	HDEVINFO hDevInfo;  
    	SP_DEVINFO_DATA DeviceInfoData;  
    	const static LPCTSTR arPrefix[3] = {TEXT("VID_"), TEXT("PID_"), TEXT("MI_")};  
    	TCHAR szDeviceInstanceID [MAX_DEVICE_ID_LEN];  
    	TCHAR szDesc[1024], szHardwareIDs[4096];  
    	WCHAR szBuffer[4096];  
    	LPTSTR pszToken, pszNextToken;  
    	TCHAR szVid[MAX_DEVICE_ID_LEN], szPid[MAX_DEVICE_ID_LEN], szMi[MAX_DEVICE_ID_LEN];  
    	FN_SetupDiGetDevicePropertyW fn_SetupDiGetDevicePropertyW = (FN_SetupDiGetDevicePropertyW)  
    		GetProcAddress (GetModuleHandle (TEXT("Setupapi.dll")), "SetupDiGetDevicePropertyW");  
    
    	// List all connected USB devices  
    	hDevInfo = SetupDiGetClassDevs (pClassGuid, pszEnumerator, NULL,  
    		pClassGuid != NULL ? DIGCF_PRESENT: DIGCF_ALLCLASSES | DIGCF_PRESENT);  
    	if (hDevInfo == INVALID_HANDLE_VALUE)  
    		return;  
    
    	// Find the ones that are driverless  
    	for (i = 0; ; i++)  {  
    		List_all_USB_devices usb_dev;
    
    		DeviceInfoData.cbSize = sizeof (DeviceInfoData);  
    		if (!SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData))  
    			break;  
    
    		status = CM_Get_Device_ID(DeviceInfoData.DevInst, szDeviceInstanceID , MAX_PATH, 0);  
    		if (status != CR_SUCCESS)  
    			continue;  
    
    		// Display device instance ID  
    		_tprintf (TEXT("%s\n"), szDeviceInstanceID );  
    
    		if (SetupDiGetDeviceRegistryProperty (hDevInfo, &DeviceInfoData, SPDRP_DEVICEDESC,  
    			&dwPropertyRegDataType, (BYTE*)szDesc,  
    			sizeof(szDesc),   // The size, in bytes  
    			&dwSize))  
    			//设备名称 
    			_tprintf (TEXT("    Device Description: \"%s\"\n"), szDesc);  
    		usb_dev.Device_Description.Format(_T("%s"),szDesc);
    		if (SetupDiGetDeviceRegistryProperty (hDevInfo, &DeviceInfoData, SPDRP_HARDWAREID,  
    			&dwPropertyRegDataType, (BYTE*)szHardwareIDs,  
    			sizeof(szHardwareIDs),    // The size, in bytes  
    			&dwSize)) {  
    				LPCTSTR pszId;  
    				_tprintf (TEXT("    Hardware IDs:\n"));  
    				for (pszId=szHardwareIDs;  
    					*pszId != TEXT('\0') && pszId + dwSize/sizeof(TCHAR) <= szHardwareIDs + ARRAYSIZE(szHardwareIDs);  
    					pszId += lstrlen(pszId)+1) {  
    
    						_tprintf (TEXT("        \"%s\"\n"), pszId); 
    						usb_dev.pszId.Format(_T("%s"),pszId);
    				}  
    		}  
    
    		// Retreive the device description as reported by the device itself  
    		// On Vista and earlier, we can use only SPDRP_DEVICEDESC  
    		// On Windows 7, the information we want ("Bus reported device description") is  
    		// accessed through DEVPKEY_Device_BusReportedDeviceDesc  
    		if (fn_SetupDiGetDevicePropertyW && fn_SetupDiGetDevicePropertyW (hDevInfo, &DeviceInfoData, &DEVPKEY_Device_BusReportedDeviceDesc,  
    			&ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize, 0)) {  
    				//设备类型
    				if (fn_SetupDiGetDevicePropertyW (hDevInfo, &DeviceInfoData, &DEVPKEY_Device_BusReportedDeviceDesc,  
    					&ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize, 0))  
    					_tprintf (TEXT("    Bus Reported Device Description: \"%ls\"\n"), szBuffer);  
    				usb_dev.Bus_Reported_Device_Description = szBuffer;
    
    				if (fn_SetupDiGetDevicePropertyW (hDevInfo, &DeviceInfoData, &DEVPKEY_Device_Manufacturer,  
    					&ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize, 0)) {  
    						_tprintf (TEXT("    Device Manufacturer: \"%ls\"\n"), szBuffer); 
    						usb_dev.Device_Manufacturer = szBuffer;
    				}  
    				if (fn_SetupDiGetDevicePropertyW (hDevInfo, &DeviceInfoData, &DEVPKEY_Device_FriendlyName,  
    					&ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize, 0)) {  
    						_tprintf (TEXT("    Device Friendly Name: \"%ls\"\n"), szBuffer); 
    						usb_dev.Device_Friendly_Name = szBuffer;
    				}  
    				if (fn_SetupDiGetDevicePropertyW (hDevInfo, &DeviceInfoData, &DEVPKEY_Device_LocationInfo,  
    					&ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize, 0)) {  
    						_tprintf (TEXT("    Device Location Info: \"%ls\"\n"), szBuffer);  
    						usb_dev.Device_Location_Info = szBuffer;
    				}  
    				if (fn_SetupDiGetDevicePropertyW (hDevInfo, &DeviceInfoData, &DEVPKEY_Device_SecuritySDS,  
    					&ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize, 0)) {  
    						// See Security Descriptor Definition Language on MSDN  
    						// (http://msdn.microsoft.com/en-us/library/windows/desktop/aa379567(v=vs.85).aspx)  
    						_tprintf (TEXT("    Device Security Descriptor String: \"%ls\"\n"), szBuffer);  
    						usb_dev.Device_Security_Descriptor_String = szBuffer;
    				}  
    				//容器ID
    				if (fn_SetupDiGetDevicePropertyW (hDevInfo, &DeviceInfoData, &DEVPKEY_Device_ContainerId,  
    					&ulPropertyType, (BYTE*)szDesc, sizeof(szDesc), &dwSize, 0)) {  
    						StringFromGUID2((REFGUID)szDesc, szBuffer, ARRAY_SIZE(szBuffer));  
    						_tprintf (TEXT("    ContainerId: \"%ls\"\n"), szBuffer);  
    						usb_dev.ContainerId = szBuffer;
    				}  
    				if (fn_SetupDiGetDevicePropertyW (hDevInfo, &DeviceInfoData, &DEVPKEY_DeviceDisplay_Category,  
    					&ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize, 0))  
    					_tprintf (TEXT("    Device Display Category: \"%ls\"\n"), szBuffer); 
    				usb_dev.Device_Display_Category = szBuffer;
    		}  
    
    		pszToken = _tcstok_s (szDeviceInstanceID , TEXT("\\#&"), &pszNextToken);  
    		while(pszToken != NULL) {  
    			szVid[0] = TEXT('\0');  
    			szPid[0] = TEXT('\0');  
    			szMi[0] = TEXT('\0');  
    			for (j = 0; j < 3; j++) {  
    				if (_tcsncmp(pszToken, arPrefix[j], lstrlen(arPrefix[j])) == 0) {  
    					switch(j) {  
    					case 0:  
    						_tcscpy_s(szVid, ARRAY_SIZE(szVid), pszToken);  
    						break;  
    					case 1:  
    						_tcscpy_s(szPid, ARRAY_SIZE(szPid), pszToken);  
    						break;  
    					case 2:  
    						_tcscpy_s(szMi, ARRAY_SIZE(szMi), pszToken);  
    						break;  
    					default:  
    						break;  
    					}  
    				}  
    			}  
    			if (szVid[0] != TEXT('\0'))  
    			{
    				_tprintf (TEXT("    vid: \"%s\"\n"), szVid);  
    				usb_dev.szVid.Format(_T("%s"),szVid);
    			}
    
    			if (szPid[0] != TEXT('\0'))  
    			{
    				_tprintf (TEXT("    pid: \"%s\"\n"), szPid);
    				usb_dev.szPid.Format(_T("%s"),szPid);
    			}
    
    			if (szMi[0] != TEXT('\0'))  
    			{
    				_tprintf (TEXT("    mi: \"%s\"\n"), szMi);  
    				usb_dev.szMi.Format(_T("%s"),szMi);
    			}
    
    			pszToken = _tcstok_s (NULL, TEXT("\\#&"), &pszNextToken);  
    		}  
    
    		Usb_Devices.push_back(usb_dev);
    	}  
    
    	return;  
    }  
    
    
    
    bool Usb_List_Data::GetAllUsbInfo(std::vector<List_all_USB_devices> & usb_Info)
    {
    	ListDevices(NULL, _T("USB"));
    	usb_Info = Usb_Devices;
    	return (usb_Info.size() > 0 ? true : false);
    }
    
    
    
    std::vector<HostControllers> host;
    
    
    bool Usb_Id::GetAllUsbPlace(std::vector<HostControllers> & usb_host)
    {
    	GetAllUsbPlace_();
    	usb_host = host;
    	return (usb_host.size() > 0 ? true : false);
    }
    
    
    void Usb_Id::GetAllUsbPlace_()
    {
    	host.clear();
    	EnumerateHostControllers(0,&devicesConnected);
    }
    
    
    
    void Usb_SequenceInfo::GetUsbPortsInfo()
    {
    	std::vector<List_all_USB_devices> usb_data;
    	usb_list.GetAllUsbInfo(usb_data);
    
    	std::vector<HostControllers> usb_host;
    	Usb_id.GetAllUsbPlace(usb_host);
    	WriteUsbPortsInfo(usb_data,usb_host);
    }
    
    void Usb_SequenceInfo::WriteUsbPortsInfo(std::vector<List_all_USB_devices> usb_data,std::vector<HostControllers> usb_host)
    {
    	if (0 >= usb_data.size() && 0 >= usb_host.size())
    	{
    		AfxMessageBox(_T("无法获取到USB的接口位置!"));
    	}
    	//合并信息组成一条完整usb设备信息
    	m_port.clear();
    	int count = 0;
    	for (auto it = usb_host.begin();it != usb_host.end();it++)
    	{
    		for (auto Usb = it->Hub.begin();Usb != it->Hub.end();Usb++)
    		{
    			for (auto UsbInfo = Usb->Usb.begin();UsbInfo != Usb->Usb.end();UsbInfo++)
    			{
    				Usb_Port port;
    				port.ConnectionStatus = UsbInfo->ConnectionStatus;
    				if (DeviceConnected == port.ConnectionStatus)
    				{
    					if ((UsbInfo->connectionInfoEx) && (NULL !=  UsbInfo->connectionInfoEx) /*&& (0 != *UsbInfo->connectionInfoEx->DeviceDescriptor)*/)
    					{
    						port.VendorID = UsbInfo->connectionInfoEx->DeviceDescriptor.idVendor;
    						port.ProductID = UsbInfo->connectionInfoEx->DeviceDescriptor.idProduct;
    
    						//设备的id数字有的是16进制 有的是10进制
    						CString StrVendor,StrProduct;
    						StrVendor.Format(_T("VID_%04X"),port.VendorID);
    						StrProduct.Format(_T("PID_%04X"),port.ProductID);
    					
    						CString StrVendor_,StrProduct_;
    						StrVendor_.Format(_T("VID_%d"),port.VendorID);
    						StrProduct_.Format(_T("PID_%d"),port.ProductID);
    						//在所有设备信息里进行匹配
    						for (auto data = usb_data.begin();data != usb_data.end();data++)
    						{
    							if (data->bIs == true)
    								continue;
    							//进行记录数据,然后继续遍历相同容器ID的
    							if ((data->szVid == StrVendor && data->szPid == StrProduct)
    								|| (data->szVid == StrVendor_ && data->szPid == StrProduct_))
    							{
    								port.szVid = data->szVid;
    								port.szPid = data->szPid;
    								data->bIs = true;
    								port.Device_Description = data->Device_Description;
    								port.Bus_Reported_Device_Description = data->Bus_Reported_Device_Description;
    								port.Device_Manufacturer = data->Device_Manufacturer;
    								port.Device_Location_Info = data->Device_Location_Info;
    								port.ContainerId = data->ContainerId;
    								port.szMi = data->szMi;
    								if (!port.ContainerId.IsEmpty())
    								{
    									//遍历一边相同容器ID的信息,找出设备名称
    									for (auto data1 = usb_data.begin();data1 != usb_data.end();data1++)
    									{
    										if (port.ContainerId == data1->ContainerId)
    										{
    											if (!data1->bIs)
    											{
    												//如果设备描述已经是Android了,那么修改为设备名称
    												/*
    												这么做的原因是Device_Description或Bus_Reported_Device_Description其中有一个表示设备名称,
    												遍历的时候可能会被Android字节覆盖掉,这样可以保证保留设备名称
    												*/
    												if (port.Device_Description1.IsEmpty() || _T("Android") != data->Bus_Reported_Device_Description)
    												{
    													port.Device_Description1 = data1->Device_Description;
    												}
    												data1->bIs = true;
    											}
    										}
    									}
    								}
    							}
    
    
    						}
    
    					}
    				}
    				port.nCount = ++count;
    				m_port.push_back(port);
    			}
    		}
    	}
    }
    
    
    bool Usb_SequenceInfo::GetUsbAllPorts(std::vector<Usb_Port> & port)
    {
    	GetUsbPortsInfo();
    	port = m_port;
    	return (port.size() > 0 ? true : false);
    }
    

      MFC工程下载地址:https://download.csdn.net/download/a29562268/10294175!这个项目可以顺利执行,如果有报错的情况,请参考前面配置的时候是否没有配置正确!

    展开全文
  • 启用前置音频插口

    2013-08-06 10:24:04
    耳机前置插口不能启用,纠结了好久终于找到解决方案分享一下。
  • 电脑主机板插口详图

    2014-10-20 11:23:59
    电脑主机板插口详图 很详细哦
  • TCP/IP 插口

    2019-05-18 21:05:00
    插口层与协议的具体实现相关。 引言:重点是插口层和相关的系统调用的实现是最关键的问题。 splnet处理,重点要理解插口层和系统调用的实现。 Socket结构 一直被广泛使用的socket结构和插口层的使用有很大的...

      插口层与协议的具体实现相关。

    引言:重点是插口层和相关的系统调用的实现是最关键的问题。

    splnet处理,重点要理解插口层和系统调用的实现。

     

    Socket结构

    一直被广泛使用的socket结构和插口层的使用有很大的关系。插口代表一条通信链路的一端,抽象的说就像绳子的一头,绳子代表存储和指向链路有关的信息。

    理解成网线的插口比较好。。。今天华为被怼了,很不爽。特朗普有病。。包括贸易战的大节奏。

    getsocketopt和setsocketopt 的系统调用能修改大部分的插口选项。。。。

    struct socket定义 不必要记 关注它定义了哪些结构。

     

    SS_NBIO :内核不阻塞进程。

    SS_ASYNC:内核发送SIGIO信号给so_pgid标识。

     

    主要看函数的调用和进程之间的关系。很无聊。只是一个载体。

     

    系统调用

    每一个系统调用均被编号,当进程执行一个系统调用时,硬件被配置或传输控制给一个内核函数。

    内核函数syscall,是为了找sysent结构。

    ssocket可以作为系统调用的例子。只要看三点就可以。

    1建立服务器客户端和客户,终止类系统调用。2输入输出类系统调用。3管理类系统调用。

     

    网络系统调用流程要仔细看。socket主要是开或关,读写,监听,连接。

     

    进程,描述符和插口

    这三个名称是为了给系统调用做基础的。三个名词,只有描述符比较陌生。比较无聊。。。

     

    socket系统调用

    socket系统调用生产一个新的插口,并将制定的协议连接起来。

    socket的系统调用是一个简单的例子,关系到很多函数。没什么作用,无聊。

    socket只是一个例子,插口层的存在在哪里是更重要的事情。

     

    bind系统调用

    bind系统调用将本地的网络运输层地址和插口层联系起来。进程需要绑定要地址,因此进程在接受TCP和接受UDP之前必须调用bind函数。

    寻找插口和本地地址的连接。

     

    listen系统调用

    通知协议进程准备接受插口的请求。当由插口来了,listen就负责通知。

    还有tsleep函数,wakeup函数,accept函数sonewconn,soisconnested函数

     

    connect系统调用

    服务器进程调用listenhe accept调用等待远程初始化。进程愿意自己初始化,则调用connect函数。

    重点是connect处理过程。

     

    shutdown系统调用

    顾命思意就是,就是关闭插口通道。

     

    close系统调用

    关闭各类描述符。

     

    小结

    本节主要讲了网络操作相关的系统调用。但是插口层的他妈的具体在哪里,我目前还不是很明白。。。希望以后的学习中,可以补齐。

     

    今天状态不佳,。。

     

    转载于:https://www.cnblogs.com/lordwind/p/10887085.html

    展开全文
  • TCP/IP 插口选项

    2019-05-20 18:03:00
    引言 本文会对插口层做一个了断。插口层的修改和系统调用将在本节讨论。 主要函数是setsockopt getsockopt系统调用 ...sosetopt函数处理所有插口级的选项,并且将其他的选项传给插口相关联的pr_ctlout...

    引言

    本文会对插口层做一个了断。插口层的修改和系统调用将在本节讨论。

    主要函数是setsockopt getsockopt系统调用

     

    setsocketopt函数

    此函数可以访问不同的协议层。主要应用是对于setsocketopt和getsocketopt选项。

     

    sosetopt函数

    sosetopt函数处理所有插口级的选项,并且将其他的选项传给插口相关联的pr_ctloutput函数。

     

    getsockopt系统调用

    作用是返回进程请求的插口和协议选项。

    sogetopt函数类似于sosetopt函数,处理插口级选项,并将其他选项传递给与插口相关联的协议。

     

    后续还有一些函数的系统调用,就不一一列举了。

    fcntl,ioctl,getsockname,getpeername四个函数的系统调用。

    getsockname得到绑定在插口上的本地地址,将他存入制定的还蠢中。主要运用在,当在一个隐式的内核中选定了一个地址,或者在一个现实的bind调用中指定了一个通配符时,该函数就很有用了。

     

    getpeername系统调用,系统调用指定返回指定插口上连接的远端地址,当调用accept的进程通过fork和exec启动一个服务器时,就要调用该函数。因为系统不能得到accept返回的远端地址,因此只能调用getpeername。

    TP4,利用accept返回插口上的连接需要验证,这里需要getpeername的返回地址。

     

    小结:

    插口层已经讲完。ok..............Bye.

    转载于:https://www.cnblogs.com/lordwind/p/10895638.html

    展开全文
  • 简单要素 一个非常简单的插口附加组件
  • 更好的工具 最佳的插口开发工具 如何使用它
  • HDMI 插口座(19P)Altium PCB封装直接使用,更新3D模型 其他PCB软件自行转格式
  • TCP插口编程.doc.docx

    2012-09-24 10:21:39
    主要介绍基于插口API的TCP插口编程,即利用TCP插口访问TCP协议提供的服务来实现应用进程间的通信。TCP是TCP/IP体系中的运输层协议,是面向连接的,因而可提供可靠的、按序传送数据的服务。TCP提供的连接是双向的,即...
  • TCP/IP: 插口I/O

    2019-05-20 09:09:00
    插口层对应的O/I,主要是用于发送数据,接收数据,数据的select选择。 插口缓存: 缓存的概念是很明白的,每个插口都有一个发送缓存和一个接收缓存。设置缓存是为了加快读取和输出速度。 插口宏和函数 ...
  • 派特莱PHU-3 系列使用USB插口控制的信号灯样本pdf,USB接口连接,无需附加电源,可通过计算机控制,作为计算机报警辅助提示工具易识别,简便有效。
  • 端口(port)和插口(socket)的区别

    千次阅读 2019-05-01 22:47:40
    插口包含了端口,因为插口 = (IP地址,端口号)。插口是TCP连接的端点。 插口(socket)有多种意思。当使用API时,插口往往被看成是操作系统的一种抽象,这时,插口和一个文件描述符是很相似的,并且是应用编程接口API...
  • vue中slot插口的用法

    千次阅读 2017-07-19 16:16:06
    关于vue中slot插口的作用可以借助input中的placeholder属性来理解。
  • 派特莱PHU-3 系列使用USB插口控制的信号灯2D CADpdf,USB接口连接,无需附加电源,可通过计算机控制,作为计算机报警辅助提示工具易识别,简便有效。
  • 一开始可能是这样的, 勾选前面板 然后插入耳机,就可以使用了。 可能之前默认耳机的插口在机箱后面。现在就在前面了。 参考文章 参考 参考
  • 用MFC制作的顺序显示所有USB插口(已经插入和未插入的),设备遍历显示的原理来自USB View,设备的重要数据信息来自WindowAPI函数,通过这两套函数与一套结合算法,成功显示出所有的设备,并且保存了重要的数据信息,...
  • 如何区分USB 2.0 和USB 3.0插口 https://jingyan.baidu.com/article/a948d65165138d0a2dcd2ec9.html
  • Socketer_1.0_Win32简易的插口调试器
  • 一.概述 插口层可以说是在用户程序与TCP/IP协议之间的一个呈上启下的层次,它将用户与某协议相关的请求映射到具体的协议实现。... 插口也就是我们常说的套接字,它代表了一条通信链路的一端,插口结构中存储或...
  • A.6 插口排错选项 查看一个T C P连接上发生的事情的另一种方法是使能插口排错选项,当然是在支持这一特征的系统中。这个特征只能工作在 T C P上(其他协议都不行),并且需要应用程序支持(当应用程序启动时,使能一...
  • Ghutenshtoff-工具包 一个有用的插口命令的简单工具包,简短而可爱,没有多余的膨胀!
  • 装完电脑后,想听听音乐,发现电脑前面插口没有声音--是一件很蛋疼的事 解决方案如下: 1.检查声卡驱动 2.设置前面插口可以正常使用,一般AC97前面的板藏的非常深,不好找到,找到问题就迎刃而解了。
  • 光纤网卡(FiberEthernet Adapter)按主板插口类型分,通常有PCI、PCI-X、PCI-E等类型。光纤网卡的主板插口类型决定了其适配性。因此,用户需要根据自己的光纤到存储或光纤到服务器组网的实际情况选择合适的网卡,以...
  • 插口红源代码H5

    2019-01-08 13:59:59
    开源女生赢口红,全开源的HTML5源码。最新的最全的插红口红代码;
  • type-c插口,什么意思?

    千次阅读 2017-11-28 16:35:34
    1)type-c插口,是那种正反都可以插的,即不分正反面的。 2)不是所有不分正反面的都是type-c,iphone 5s也是不分正反面的,但是不是type-c 所以,手机被淘汰,不是因为手机性能不行了,而是手机功能不能满足...
  • 光纤网卡(Fiber Ethernet Adapter)按主板插口类型分,通常有PCI、PCI-X、PCI-E等类型。光纤网卡的主板插口类型决定了其适配性。因此,用户需要根据自己的光纤到存储或光纤到服务器组网的实际情况选择合适的网卡,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,261
精华内容 904
关键字:

插口