当前位置:首页 > server
  • 浅谈从Linux源码分析bind系统调用

    浅谈从Linux源码分析bind系统调用

    作者一直认为,从应用程序到框架再到系统,使用每一个代码是一回事理解。使用“今天,作者将研究服务器端套接字的功能。准确地说,它是bind(基于linux3.10)。 一个最简单的Server端例子 众所周知,一个Server端Socket的建立,需要socket、bind、listen、accept四个步骤。  代码如下: 首先我们通过socket系统调用创建了一个socket,其中指定了SOCK_STREAM,而且最后一个参数为0,也就是建立了一个通常所有的TCP Socket。在这里,我们直接给出TCP Socket所对应的ops也就是操作函数。  如果你想知道上图中的结构是怎么来的,可以看下笔者以前的博客:   bind系统调用 bind将一个本地协议地址(protocol:ip:port)赋予一个套接字。例如32位的ipv4地址或128位的ipv6地址+16位的TCP活UDP端口号。 好了,我们直接进入Linux源码调用栈吧。 inet_bind inet_bind这个函数主要做了两个操作,一是检测是否允许bind,而是获取可用的端口号。这边值得注意的是。如果我们设置需要bind的端口号为0,那么Kernel会帮我们随机选择一个可用的端口号来进行bind! 让我们看下inet_bind的流程  值得注意的是,由于对于sk_prot->get_port) inet_csk_get_port 第一段,如果bind port为0,随机搜索可用端口号 直接上源码,第一段代码为端口号为0的搜索过程 由于,我们在使用bind的时候很少随机端口号(在TCP服务器来说尤其如此),这段代码笔者就注释一下。一般只有一些特殊的远程过程调用(RPC)中会使用随机Server端随机端口号。 第二段,找到端口号或已经指定 判断端口号是否冲突 在上述源码中,判断端口号时否冲突的代码为 上面代码的逻辑如下图所示:  SO_REUSEADDR和SO_REUSEPORT 上面的代码有点绕,笔者就讲一下,对于我们日常开发要关心什么。 我们在上面的bind里面经常见到sk_reuse和sk_reuseport这两个socket的Flag。这两个Flag能够决定是否能够bind(绑定)成功。这两个Flag的设置在C语言里面如下代码所示: 在原生JAVA中 在Netty(Netty版本 >= 4.0.16且Linux内核版本>=3.9以上)中,可以使用SO_REUSEPORT。 SO_REUSEADDR 在之前的源码里面,我们看到判断bind是否冲突的时候,有这么一个分支 如果sk2(即已bind的socket)是TCP_LISTEN状态或者,sk2和新sk两者都没有设置_REUSEADDR的时候,可以判断为冲突。 我们可以得出,如果原sock和新sock都设置了SO_REUSEADDR的时候,只要原sock不是Listen状态,都可以绑定成功,甚至ESTABLISHED状态也可以!  这个在我们平常工作中,最常见的就是原sock处于TIME_WAIT状态,这通常在我们关闭Server的时候出现,如果不设置SO_REUSEADDR,则会绑定失败,进而启动不来服务。而设置了SO_REUSEADDR,由于不是TCP_LISTEN,所以可以成功。  这个特性在紧急重启以及线下调试的非常有用,建议开启。 SO_REUSEPORT SO_REUSEPORT是Linux在3.9版本引入的新功能。 我们看下一般的Reactor线程模型,  明显的其单线程listen/accept会存在瓶颈(如果采用多线程epoll accept,则会惊群,加WQ_FLAG_EXCLUSIVE可以解决一部分),尤其是在采用短链接的情况下。 鉴于此,Linux增加了SO_REUSEPORT,而之前bind中判断是否冲突的下面代码也是为这个参数而添加的逻辑: 这段代码让我们在多次bind的时候,如果设置了SO_REUSEPORT的时候不会报错,也就是让我们有个多线程(进程)bind/listen的能力。如下图所示:  而开启了SO_REUSEPORT后,代码栈如下: 直接在内核层面做负载均衡,将accept的任务分散到不同的线程的不同socket上(Sharding),毫无疑问可以多核能力,大幅提升连接成功后的socket分发能力。 Nginx已经采用SO_REUSEPORT Nginx在1.9.1版本的时候引入了SO_REUSEPORT,配置如下:   总结 Linux有一个非常复杂的内核源代码,希望能对读者有所帮助。

    时间:2020-10-17 关键词: Linux bind server

  • 基于网络回溯分析技术的SCADA系统故障诊断

    基于网络回溯分析技术的SCADA系统故障诊断

      案例场景   某排水集团在线业务区的SCADA系统需要从DMZ区的I/O Server上采集数据,SCADA系统使用某些IP能够正常从I/O Server采集数据,但是另一部分IP则不能正常的从I/O Server上采集数据,提示异常并且断开连接。   例如:10.2.103.8为SCADA系统的IP地址,能够正常的从10.2.0.51和10.2.0.52的I/O Server上采集数据,但是将SCADA系统的IP改为:10.2.103.10,则不能正常从10.2.0.51和10.2.0.52的I/O Server上采集数据。   案例分析   网络拓扑图(简化)   下图为简化拓扑图,我们展示SCADA系统和I/O Server之间的通讯链路,分别在靠近SCADA系统和I/O Server的接入交换机上采用端口镜像的方式旁路部署科来网络回溯分析系统,采集SCADA系统和I/O Server之间的通讯数据包。      图1网络拓扑图   故障排查   我们从DMZ区的交互机和在线业务区交互机上同时采集通讯数据,进行对比分析,来看看具体是什么原因造成了业务系统的故障。   DMZ区交换机数据   在DMZ区交换机数据中可以看到TCP会话中10.2.103.10向10.2.0.52发送了大量的RST(复位)数据包,如下图2所示。这些连接被这些复位数据包释放掉了,但是为什么会存在这么多的复位数据包?又是谁发送了这些数据包?      图2 DMZ区捕获到的TCP会话   通过查看科来网络回溯分析系统的交易时序图,可以发现复位数据包的TTL(生存时间)值是127.而正常时传输的数据,可以看到TTL(生存时间)值为61,和异常时明显不同,说明复位数据包并不是从10.2.103.10发出来的,而是有个中间设备发送了复位数据包中断了正常的应用会话。

    时间:2020-09-03 关键词: scada 数据包 server

  • 腾讯云服务器选择Linux系统还是Windows Server镜像?

    腾讯云服务器选择Linux系统还是Windows Server镜像?

    如何选择腾讯云服务器操作系统? 腾讯云服务器操作系统通过镜像安装。 哪个最适合腾讯云镜像? 服务器选择镜像Linux系统还是Windows服务器? 云服务器栏(yunfuwuqiba.com)说明了腾讯云服务器的镜像列表以及操作系统选择方法: 腾讯云服务器操作系统是通过镜像的方式来安装的,腾讯云服务器选哪个操作系统?腾讯云服务器操作系统分为Linux和Windows Server两类,云服务器吧(yunfuwuqiba.com)举例说明: Linux类镜像:CentOS、CoreOS、Debian、FreeBSD、openSUSE、Ubuntu、SUSE和Tencent Linux等; Windows Server镜像:Windows Server 2012/2016/2019 R2数据中心版/英文版等版本。 腾讯云服务器操作系统的选择,首先确定选择Windows系统还是Linux系统。服务器Windows操作系统简单易操作,Linux操作系统更少占用系统资源,如何选择可以根据实际应用场景所使用的编程语言来选择合适的操作系统。一般来讲ASP、.NET、HTML、数据库ACCESS、SQL Server可以选择Windows镜像;PHP、PERL、CGI、数据库MySQL、SQLite可以选择Linux系统。 腾讯云服务器如果是选择Windows镜像,云服务器吧建议选择Windows Server 2012 R2 数据中心版 64位中文版;如果是Linux镜像,云服务器建议选择CentOS 7.2 64位或Ubuntu Server 16.04.1 LTS 64位。只是建议,实际操作系统建议根据本身语言程序运行环境来选择合适的操作系统版本。至于服务器操作系统选择32位还是64位?云服务器吧建议选择64位操作系统。 最后,腾讯云服务器镜像是可以免费更换的,如果操作系统选择的不合适,可以在云服务器控制台,通过重装系统的方式来更换操作系统。 关于重装系统需要注意的是,非中国大陆地域的云服务器不支持Linux类系统和Windows系统互换。

    时间:2020-08-29 关键词: Windows 腾讯云 Linux server

  • SQL Server数据库学习之 -- 存储过程-游标-表值类型综合运用

          我在工作中,根据项目中的需求,需要编写存储过程,进行对数据批量处理。根据在项目中运用的知识点,我简写一个存储过程的内容,以另一个场景将所运用到的知识写下来: USE [B2C2] -- 使用B2C2数据库 SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= /* 创建表值类型 clazz_Table */ CREATE TYPE clazz_Table AS TABLE ( TEACHER varchar(128), -- 班主任 CLANO varchar(64), -- 班级编号 SEX char(8), -- 性别 NAME varchar(128), -- 姓名 AGE int, -- 年龄 STUNO int -- 学号 ) GO CREATE PROCEDURE [dbo].[proc_test01] ( -- 设置全局变量 @re_table clazz_Table READONLY, @D_COUNT INT OUTPUT -- 输出参数 ) AS BEGIN -- 设置局部变量 DECLARE @D_TEACHER varchar(128); -- 班主任 DECLARE @D_CLANO varchar(64); -- 班级编号 DECLARE @D_SEX char(8); -- 性别 DECLARE @D_NAME varchar(128); -- 姓名 DECLARE @D_AGE int; -- 年龄 DECLARE @D_STUNO int; -- 学号 SET @D_COUNT = 0; -- 初始设置值为0 -- 声明一个游标 DECLARE myCursor CURSOR FOR SELECT TEACHER, CLANO, SEX, NAME, AGE, STUNO FROM @re_table; -- 打开游标 OPEN myCursor; -- 从游标中读取数据赋值到声明的6个变量中 FETCH NEXT FROM myCursor INTO @D_TEACHER, @D_CLANO, @D_SEX, @D_NAME, @D_AGE, @D_STUNO; -- 判断游标的状态 -- 0 fetch语句成功 -- 1 fecthc语句失败或此行不在结果中 -- 2 被提取的行不存在 WHILE(@@FETCH_STATUS = 0) -- @@FETCH_STATUS为SQL Server数据库中内置的变量,可直接拿来使用。 BEGIN -- 使用游标分条读取从Java代码端传递过来的clazz_Table数据 INSERT INTO t_clazz(teacher, clano, sex, name, age, stuno) VALUES(@D_TEACHER, @D_CLANO, @D_SEX, @D_NAME, @D_AGE, @D_STUNO); -- 用游标去取下一条记录 FETCH NEXT FROM myCursor INTO @D_TEACHER, @D_CLANO, @D_SEX, @D_NAME, @D_AGE, @D_STUNO; END -- 设置@D_COUNT的值 SET @D_COUNT = 1; -- 关闭游标 CLOSE myCursor; -- 撤销游标 DEALLOCATE myCursor; END GO

    时间:2019-12-09 关键词: 存储过程 sql server

  • Sql Server的存储过程与Java代码相连接调用(二)

                            我所写的项目是使用Maven开发,在pom.xml中添加如下必要依赖:         添加com.microsoft.sqlserver的mssql-jdbc 6.2.1.jre8的依赖 com.microsoft.sqlserver mssql-jdbc 6.2.1.jre8                  在下面的Java代码块中,涉及到如何在Java中创建SQL Server的“表值变量”(临时表),以及Java代码如何去调用SQL Server的存储过程,如何传递在Java代码中所写的“表值变量”(临时表)。其中,代码中所调用的 proc_test01存储过程,可参考我写的博客:SQL Server数据库学习之 -- 存储过程-游标-表值类型综合运用                我所写的代码有些简化,以“学生 -- 班级 -- 教师”这种经典模式来讲解自己所运用的知识点。可能网友直接将我的代码粘贴-复制,运行会报错。不过其中的知识点确是无误的!         在本篇文章中,最重要的是其运用到SQL Server表值类型变量这块知识。关于在Java代码中引入的Sql Server-Jar包,不能太低,否则无法使用“表值类型变量”这块知识。  import java.util.Map; import com.microsoft.sqlserver.jdbc.SQLServerCallableStatement; import com.microsoft.sqlserver.jdbc.SQLServerDataTable; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.CallableStatementCallback; import org.springframework.jdbc.core.CallableStatementCreator; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; @Service public class ClazzService { /** * 批量提交班级信息 */ public int putClazz(Clazz clazz) throws SQLException { Integer count = 0; Integer testCount = sqlServerJdbcTemplate.execute( new CallableStatementCreator() { @Override public CallableStatement createCallableStatement(Connection con) throws SQLException { SQLServerCallableStatement cs = (SQLServerCallableStatement) con.prepareCall("exec proc_test01 ?, ?"); // 设置存储过程中所用的临时表名 SQLServerDataTable sourceDataTable = new SQLServerDataTable(); // 为临时表sourceDataTable添加表头字段和字段类型 sourceDataTable.addColumnMetadata("TEACHER", java.sql.Types.VARCHAR); sourceDataTable.addColumnMetadata("CLANO", java.sql.Types.VARCHAR); sourceDataTable.addColumnMetadata("SEX", java.sql.Types.CHAR); sourceDataTable.addColumnMetadata("NAME", java.sql.Types.VARCHAR); sourceDataTable.addColumnMetadata("AGE", java.sql.Types.INTEGER); sourceDataTable.addColumnMetadata("STUNO", java.sql.Types.INTEGER); // 可一次性将多个不同学生插入到同一个班级中 for (Student student : clazz.getStudent()) { // 将数据添加进创建的Table表中 sourceDataTable.addRow(clazz.getTeacher(), clazz.getClaNo(), student.getSex(), student.getName(), student.getAge(), student.getStuNo()); } // 字符串"clazz_Table"为调用数据库存储过程“proc_test01”中,其内部编写的临时表名称 cs.setStructured(1, "clazz_Table", sourceDataTable); cs.registerOutParameter(2, java.sql.Types.INTEGER); // 可返回值的参数 return cs; } }, new CallableStatementCallback() { @Override public Integer doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException { cs.execute(); return cs.getInt(2); // 将第“2”个参数的值返回。第“2”个参数,其类型是“返回值类型参数” } } ); count = testCount; // 将testCount变量赋值给count变量 return count; } // public int putClazz(Clazz clazz) } Student.java类(学生类),其代码如下 package com.entity; public class Student { private char sex; // 性别 private String name; // 姓名 private int age; // 年龄 private int stuNo; // 学号 public char getSex() { return sex; } public void setSex(char sex) { this.sex = sex; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getStuNo() { return stuNo; } public void setStuNo(int stuNo) { this.stuNo = stuNo; } } Clazz.java类(班级类) package com.entity; import java.util.List; public class Clazz { private String teacher; // 班主任 private String claNo; // 班级编号 private List stuList; //学生 public String getTeacher() { return teacher; } public void setTeacher(String teacher) { this.teacher = teacher; } public String getClaNo() { return claNo; } public void setClaNo(String claNo) { this.claNo = claNo; } public List getStuList() { return stuList; } public void setStuList(List stuList) { this.stuList = stuList; } } -------------------------------------------------------------------------- -------------------------------------------------------------------------- 例如,写一接口,调用putClazz()函数,则可传递一组JSON数据,其数据格式如下所示。通过调用putClazz()函数,可以做到在一次提交数据过程中:一个班级可以插入多个学生信息。 JSON格式代码: { "teacher": "吴老师", "clano": "打杂1班", "stuList": [ { "sex": "男", "name": "吃瓜群众", "age": 18, "stuNo": 101001 }, { "sex": "女", "name": "如花", "age": 16, "stuNo": 101002 }, { "sex": "女", "name": "龅牙珍", "age": 20, "stuNo": 101001 } ] }

    时间:2019-12-09 关键词: 存储过程 sql server

  • Sql Server的存储过程与Java代码相连接调用(一)

               我所写的项目是使用Maven开发,在pom.xml中添加如下必要依赖:           添加com.microsoft.sqlserver的mssql-jdbc 6.2.1.jre8的依赖 com.microsoft.sqlserver mssql-jdbc 6.2.1.jre8            Java后台代码如下代码块所示。其中,代码中所调用的 proc_test02存储过程,可参考我写的博客: SQL Server数据库学习之 —— 存储过程- 事务 - try-catch代码块            我所写的代码有些简化,以“学生 -- 班级 -- 教师”这种经典模式来讲解自己所运用的知识点。可能网友直接将我的代码粘贴-复制,运行会报错。不过其中的知识点确是无误的! package org.com.api.service; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.SQLException; import java.util.List; import java.util.Map; import com.microsoft.sqlserver.jdbc.SQLServerCallableStatement; import com.microsoft.sqlserver.jdbc.SQLServerDataTable; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.CallableStatementCallback; import org.springframework.jdbc.core.CallableStatementCreator; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; @Service public class ClazzService { @Autowired private JdbcTemplate jdbcTemplate; @Autowired @Qualifier("sqlServerJdbcTemplate") private JdbcTemplate sqlServerJdbcTemplate; /** * 新增学生 * @return */ public int addStudent(Student student) { Integer testCount = 0; Integer count = jdbcTemplate.execute(new CallableStatementCreator() { @Override public CallableStatement createCallableStatement(Connection con) throws SQLException { // proc_test02(?,?,?,?,?)中的问号,代表调用的存储过程“proc_test02”中的参数 CallableStatement cs = con.prepareCall("{call proc_test02(?,?,?,?,?)}"); // 为CallableStatement设置参数 cs.setString(1, student.getSex()); // 获取性别,sex字段为String类型 cs.setString(2, student.getName()); // 获取姓名,name字段为String类型 cs.setInt(3, student.getAge()); // 获取年龄,age字段为int类型 cs.setInt(4, student.getStuNo()); // 获取学号,stuNo字段为int类型 cs.registerOutParameter(5, java.sql.Types.INTEGER); // =1, 则正确! return cs; } }, new CallableStatementCallback() { @Override public Integer doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException { cs.execute(); return cs.getInt(5); } }); testCount = count; return testCount; // = 1 } }

    时间:2019-12-09 关键词: sql java web server

  • Linux系统管道和有名管道的通信机制

    Linux 进程间通信的几种主要手段。其中管道和有名管道是最早的进程间通信机制之一,管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。 认清管道和有名管道的读写规则是在程序中应用它们的关键,本文在详细讨论了管道和有名管道的通信机制的基础上,用实例对其读写规则进行了程序验证,这样做有利于增强读者对读写规则的感性认识,同时也提供了应用范例。 1、 管道概述及相关API应用 1.1 管道相关的关键概念 管道是Linux支持的最初Unix IPC形式之一,具有以下特点: 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道; 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程); 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。 数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。 1.2 管道的创建: #include int pipe(int fd[2]) 该函数创建的管道的两端处于一个进程中间,在实际应用中没有太大意义,因此,一个进程在由pipe()创建管道后,一般再fork一个子进程,然后通过管道实现父子进程间的通信(因此也不难推出,只要两个进程中存在亲缘关系,这里的亲缘关系指的是具有共同的祖先,都可以采用管道方式来进行通信)。 1.3 管道的读写规则: 管道两端可分别用描述字fd[0]以及fd[1]来描述,需要注意的是,管道的两端是固定了任务的。即一端只能用于读,由描述字fd[0]表示,称其为管道读端;另一端则只能用于写,由描述字fd[1]来表示,称其为管道写端。如果试图从管道写端读取数据,或者向管道读端写入数据都将导致错误发生。一般文件的I/O函数都可以用于管道,如close、read、write等等。 从管道中读取数据:如果管道的写端不存在,则认为已经读到了数据的末尾,读函数返回的读出字节数为0;当管道的写端存在时,如果请求的字节数目大于PIPE_BUF,则返回管道中现有的数据字节数,如果请求的字节数目不大于PIPE_BUF,则返回管道中现有数据字节数(此时,管道中数据量小于请求的数据量);或者返回请求的字节数(此时,管道中数据量不小于请求的数据量)。注:(PIPE_BUF在include/Linux/limits.h中定义,不同的内核版本可能会有所不同。Posix.1要求PIPE_BUF至少为512字节,red hat 7.2中为4096)。 关于管道的读规则验证: * readtest.c * #include #include #include main() { int pipe_fd[2]; pid_t pid; char r_buf[100]; char w_buf[4]; char* p_wbuf; int r_num; int cmd; memset(r_buf,0,sizeof(r_buf)); memset(w_buf,0,sizeof(r_buf)); p_wbuf=w_buf; if(pipe(pipe_fd)0) { close(pipe_fd[0]);//read strcpy(w_buf,"111"); if(write(pipe_fd[1],w_buf,4)!=-1) printf("parent write overn"); close(pipe_fd[1]);//write printf("parent close fd[1] overn"); sleep(10); } } 程序输出结果: * parent write over * parent close fd[1] over * read num is 4 the data read from the pipe is 111 附加结论:管道写端关闭后,写入的数据将一直存在,直到读出为止。 向管道中写入数据:向管道中写入数据时,Linux将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读走管道缓冲区中的数据,那么写操作将一直阻塞。 注:只有在管道的读端存在时,向管道中写入数据才有意义。否则,向管道中写入数据的进程将收到内核传来的SIFPIPE信号,应用程序可以处理该信号,也可以忽略(默认动作则是应用程序终止)。对管道的写规则的验证1:写端对读端存在的依赖性 #include #include main() { int pipe_fd[2]; pid_t pid; char r_buf[4]; char* w_buf; int writenum; int cmd; memset(r_buf,0,sizeof(r_buf)); if(pipe(pipe_fd)0) { sleep(1); //等待子进程完成关闭读端的操作 close(pipe_fd[0]);//write w_buf="111"; if((writenum=write(pipe_fd[1],w_buf,4))==-1) printf("write to pipe errorn"); else printf("the bytes write to pipe is %d n", writenum); close(pipe_fd[1]); } } 则输出结果为: Broken pipe,原因就是该管道以及它的所有fork()产物的读端都已经被关闭。如果在父进程中保留读端,即在写完pipe后,再关闭父进程的读端,也会正常写入pipe,读者可自己验证一下该结论。因此,在向管道写入数据时,至少应该存在某一个进程,其中管道读端没有被关闭,否则就会出现上述错误(管道断裂,进程收到了SIGPIPE信号,默认动作是进程终止)对管道的写规则的验证2:Linux不保证写管道的原子性验证 #include #include #include main(int argc,char**argv) { int pipe_fd[2]; pid_t pid; char r_buf[4096]; char w_buf[4096*2]; int writenum; int rnum; memset(r_buf,0,sizeof(r_buf)); if(pipe(pipe_fd)0) { close(pipe_fd[0]);//write memset(r_buf,0,sizeof(r_buf)); if((writenum=write(pipe_fd[1],w_buf,1024))==-1) printf("write to pipe errorn"); else printf("the bytes write to pipe is %d n", writenum); writenum=write(pipe_fd[1],w_buf,4096); close(pipe_fd[1]); } } 输出结果: the bytes write to pipe 1000 the bytes write to pipe 1000 //注意,此行输出说明了写入的非原子性 the bytes write to pipe 1000 the bytes write to pipe 1000 the bytes write to pipe 1000 the bytes write to pipe 120 //注意,此行输出说明了写入的非原子性 the bytes write to pipe 0 the bytes write to pipe 0 ...... 结论: 写入数目小于4096时写入是非原子的! 如果把父进程中的两次写入字节数都改为5000,则很容易得出下面结论: 写入管道的数据量大于4096字节时,缓冲区的空闲空间将被写入数据(补齐),直到写完所有数据为止,如果没有进程读数据,则一直阻塞。 1.4 管道应用实例: 实例一:用于shell 管道可用于输入输出重定向,它将一个命令的输出直接定向到另一个命令的输入。比如,当在某个shell程序(Bourne shell或C shell等)键入who│wc -l后,相应shell程序将创建who以及wc两个进程和这两个进程间的管道。考虑命令行:$kill -l $kill -l | grep SIGRTMIN 运行结果如下: 30) SIGPWR 31) SIGSYS 32) SIGRTMIN 33) SIGRTMIN+1 34) SIGRTMIN+2 35) SIGRTMIN+3 36) SIGRTMIN+4 37) SIGRTMIN+5 38) SIGRTMIN+6 39) SIGRTMIN+7 40) SIGRTMIN+8 41) SIGRTMIN+9 42) SIGRTMIN+10 43) SIGRTMIN+11 44) SIGRTMIN+12 45) SIGRTMIN+13 46) SIGRTMIN+14 47) SIGRTMIN+15 48) SIGRTMAX-15 49) SIGRTMAX-14 实例二:用于具有亲缘关系的进程间通信 下面例子给出了管道的具体应用,父进程通过管道发送一些命令给子进程,子进程解析命令,并根据命令作相应处理。 #include #include main() { int pipe_fd[2]; pid_t pid; char r_buf[4]; char** w_buf[256]; int childexit=0; int i; int cmd; memset(r_buf,0,sizeof(r_buf)); if(pipe(pipe_fd)0) //parent: send commands to child { close(pipe_fd[0]); w_buf[0]="003"; w_buf[1]="005"; w_buf[2]="777"; w_buf[3]="000"; for(i=0;i

    时间:2019-10-09 关键词: Linux server

  • Fedora8下编译安装使用TightVNC

    1.下载源码并解压缩 下载网址:http://www.tightvnc.com/download.php  tar xjf tightvnc-1.3.10_unixsrc.tar.bz2  cd vnc_unixsrc/ 2、编译 执行如下两个命令: [root@localhost vnc_unixsrc]cxmkmf  [root@localhost vnc_unixsrc]make World 可分别在其下的四个目录中获得四个文件。第一个为静态库,后三个为x86平台的二进制执行程序。vncvviewer为x86-linux平台的client端程序。 vncpasswd用于server侧建立密码,vncconnect为server和client二者连接之用。 vnc_unixsrc/libvncauth/libvncauth.a  vnc_unixsrc/vncviewer/vncviewer vnc_unixsrc/vncpasswd/vncpasswd vnc_unixsrc/vncconnect/vncconnect 下面的是编译server侧二进制程序 [root@localhost Xvnc]#  cd Xvnc/ [root@localhost Xvnc]# ./configure  [root@localhost Xvnc]# make 得到二进制程序: vnc_unixsrc/Xvnc/programs/Xserver/Xvnc 为启动server程序的脚本vncserver打补丁,在我的Fedora8平台上,似乎没什么区别: [root@localhost vnc_unixsrc]# patch -p1

    时间:2019-10-08 关键词: tcp server

  • Bluetooth协议栈学习之SDP

    作者: Sam (甄峰) sam_code@hotmail.com   SDP(service discoveryprotocol:服务发现协议)提供了一个方法,让应用程序检测哪些服务是可用的并探测这些可用服务的特性。 服务发现协议(SDP或BluetoothSDP)在蓝牙协议栈中对蓝牙环境中的应用程序有特殊的含意,发现哪个服务是可用的和确定这些可用服务的特征。SDP定义了bluetoothclient发现可用bluetoothserver服务和它们的特征的方法。这个协议定义了客户如何能够寻找基于特定属性的服务而不让客户知道可用服务的任何知识。SDP提供发现新服务的方法,在当客户登录到正在操作的蓝牙服务器的一个区域时是可用的时。   SDP提供了一套SDP server和SDP client之间的通讯方法。 SDPserver维护着一个服务条目列表,这个列表存放着SDPserver对应的服务以及服务特性。每个服务条目对应一个单独的服务。SDPclient可以通过发送请求得到SDP server维护的这个服务条目list.   如果SDPclient或者联系于client之上的应用程序决定使用某个service,则打开一个针对此服务的连接到服务提供者去使用此服务。SDP只是提供侦测service以及特性的方法,但不提供如何使用这些service的方法.   每个bluetooth device最多有一个SDP server. 如果某个device只作为client.则不需要拥有SDPserver.而一个bluetooth device可以同时为SDP client和SDP server.   服务条目(Service Record): 一个service就是某个实体提供一些信息,执行某种动作,或控制资源代表另一个实体。一个service可以由软件,硬件或软硬件结合提供。 SDP server维护的service条目包含在service record中。 SDP server中,每个service record由一个32位数与别的record区别。注意,只是在这个SDPserver内。   当SDP server添加或删除某个service时,不会主动提供给client.   Service 属性: 每个属性描述一个service的特征。 service属性包含两部分: attribute ID + attribute Value. 属性ID是一个16bit的值,用来和Service record内的其它属性区别开来。     Service Class: 每个server是 service class的一个实例。serviceclass定义了service(此class的实例)的每个特性。属性对应attribute ID,属性value的格式, 每个serviceclasss也指定为一个的标识符。这个标识符被包含在属性ServiceClassIDList中。并描述为UUID。     Search forservice: service search功能允许SDP client得到包含在service record 中的service属性。 可以使用属性的Universally Unique Identifiers1 (UUIDs)得到属性。

    时间:2019-09-03 关键词: service server

  • 我看好FLASH技术的原因

    我看好FLASH技术的原因 作者:沧海冷心   一、FLASH文件的流式、图形化、文件精悍、易编程等特点。由于它短小精悍,又是流媒体格式,并且已经被现在的互联网发扬光大了,它无疑将成为下一代手机网络客户端上必不可少的一个元素。随着科技的日新月异,我们将可以用手机浏览各个www站点,并且FLASH是最不需要客户端支持的、可编程的娱乐文件格式。无论是动画还是游戏,FLASH将是未来手机的一个热点,也许它的游戏可以和JAVA竞争也说不定。   二、FLASH MEDIA SERVER(以下简称FMS)的出现。Macromedia Flash Media Server 2 软件将传统的流媒体功能与灵活的开发环境结合起来, 为最广泛的群体创建和提供创新的、交互式媒体应用,支持点播视频、视频协作等。其实这些都不是重点。FMS的出现代表了FLASH从一个独立的流媒体最终文件向服务器客户端模式转变。以后可能会出现更强大功能的SERVER,甚至开发者可以自定义SERVER。而且手机的主存、媒体性能在迅速发展,这样,FLASH网游甚至FLASH手机网游就成为了可能。   三、FLASH的跨平台性。FLASH是基于浏览器插件的,由ADOBE提供。无论你用微软的WINDOWS平台,还是苹果的MAC OSX平台,甚至是LINUX平台,只要你有浏览器,只要你的浏览器支持ADOBE提供的FLASH PLAYER插件,那任何FLASH程序文件都可以在你的电脑上运行。其实这个机制和JAVA虚拟机差不多。但是FLASH的优势很明显——它的图形能力绝对是最棒的。   现在学FLASH的人也很多,大部分人比较偏重图形方面,也许是学它的人大多是美工职业的原因吧。不过我觉得它的精髓部分在于ACTION SCRIPT的编程,以后它的脚本功能和扩展库引擎会越来越多的,并且现在网上已经有一些FLASH 3D引擎的雏形了,说不定以后的3D设计游戏就在IE上玩了呢。   所以现在认真努力学好FLASH的技术,以后自身的发展并不会比.net和JAVA差,也许还会更好,毕竟未来是互联网的时代——手机、电脑、家电、汽车,甚至人类,这些一起互联。   以此文鼓励自己发奋学习FLASH技术。

    时间:2019-09-02 关键词: Flash server

  • SQL Server 2012/2016/2017 新增函数

    /**************************************************************   SQL Server 2012 新增的函数   ***************************************************************/      --  CONCAT ( string_value1, string_value2 [, string_valueN ] ) #字符串相连   SELECT CONCAT('A','BB','CCC','DDDD')   --结果:ABBCCCDDDD      --  PARSE ( string_value AS data_type [ USING culture ] ) #转换为所请求的数据类型的表达式的结果   SELECT PARSE('Monday, 13 December 2010' AS datetime2 USING 'en-US') AS Result;   SELECT PARSE('€345,98' AS money USING 'de-DE') AS Result;      SET LANGUAGE 'English';   SELECT PARSE('12/16/2010' AS datetime2) AS Result;      /*结果:   2010-12-13 00:00:00.0000000   345.98   2010-12-16 00:00:00.0000000   */      --  TRY_CAST 、TRY_CONVERT、TRY_PARSE  (TRY_PARSE 仅用于从字符串转换为日期/时间和数字类型)   SELECT TRY_CAST('test' AS float),TRY_CAST(5 AS VARCHAR)   SELECT TRY_CONVERT(float,'test'),TRY_CONVERT(VARCHAR,5)   SELECT TRY_PARSE('test' AS float),TRY_PARSE('01/01/2011' AS datetime2)   /*结果:   NULL    5   NULL    5   NULL    2011-01-01 00:00:00.0000000   */         --  CHOOSE ( index, val_1, val_2 [, val_n ] ) #返回指定索引处的项 (即返回第几个值)   SELECT CHOOSE ( 3, 'Manager', 'Director', 'Developer', 'Tester' ) AS Result;   --结果:Developer      --  IIF ( boolean_expression, true_value, false_value )    SELECT IIF ( 10 > 5, 'TRUE', 'FALSE' ) AS Result;   SELECT (CASE WHEN 10 > 5 THEN 'TRUE' ELSE 'FALSE' END) AS Result;   --结果:TRUE         --  排名函数!   SELECT *   ,ROW_NUMBER ( ) OVER (PARTITION BY MyName ORDER BY Num) AS 'ROW_NUMBER' --按顺序排名   ,DENSE_RANK ( ) OVER (PARTITION BY MyName ORDER BY Num) AS 'DENSE_RANK' --同排名的后面排名连续   ,RANK  ( ) OVER (PARTITION BY MyName ORDER BY Num) AS 'RANK'            --同排名的后面排名不连续   ,NTILE (2) OVER (PARTITION BY MyName ORDER BY Num) AS 'NTILE'           --按总数分两组,顺序排名   FROM (VALUES('AA',55),('AA',30.5),('BB',55),('BB',99),('BB',0),('BB',55))AS T(MyName,Num)   ORDER BY MyName,Num   /*   MyName  Num     ROW_NUMBER  DENSE_RANK  RANK    NTILE   ------  -----   ----------  ----------  ------  -----   AA      30.5    1           1           1       1   AA      55.0    2           2           2       2   BB      0.0     1           1           1       1   BB      55.0    2           2           2       1   BB      55.0    3           2           2       2   BB      99.0    4           3           4       2   */         --  分析函数!   SELECT *    ,CUME_DIST( )OVER (PARTITION BY MyName ORDER BY Num) AS 'CUME_DIST'     --相对(最大值)位置   ,PERCENT_RANK( )OVER (PARTITION BY MyName ORDER BY Num) AS 'PERCENT_RANK' --相对排名,排名分数参考 CUME_DIST   ,FIRST_VALUE (MyName)OVER ( ORDER BY Num ASC) AS 'FIRST_VALUE'          --Num 最低的是哪个MyName   ,LAST_VALUE  (MyName)OVER ( ORDER BY Num ASC) AS 'LAST_VALUE'           --Num 排序选底部的那个MyName   ,LAG (Num,1,0)OVER (ORDER BY Num ASC) AS 'LAG'      --上/下一行(或多行)的值移到下/上一行(或多行),方便对比   ,LEAD (Num,1,0)OVER (ORDER BY Num ASC) AS 'LEAD'    --与LAG一样,排序相反   ,PERCENTILE_CONT(0.5)WITHIN GROUP (ORDER BY Num) OVER (PARTITION BY MyName) AS 'PERCENTILE_CONT' --连续分布计算百分位数   ,PERCENTILE_DISC(0.5)WITHIN GROUP (ORDER BY Num) OVER (PARTITION BY MyName) AS 'PERCENTILE_DISC' --离散分布计算百分位数   FROM (VALUES('AA',55),('AA',30.5),('BB',55),('BB',99),('BB',0),('BB',55))AS T(MyName,Num)   ORDER BY Num ASC      /*   MyName  Num     CUME_DIST   PERCENT_RANK    FIRST_VALUE LAST_VALUE  LAG     LEAD    PERCENTILE_CONT PERCENTILE_DISC   ------  -----   ---------   ------------    ----------- ----------  -----   -----   --------------- ---------------   BB      0.0     0.25        0               BB          BB          0.0     30.5    55              55.0   AA      30.5    0.5         0               BB          AA          0.0     55.0    42.75           30.5   AA      55.0    1           1               BB          BB          30.5    55.0    42.75           30.5   BB      55.0    0.75        0.33333         BB          BB          55.0    55.0    55              55.0   BB      55.0    0.75        0.33333         BB          BB          55.0    99.0    55              55.0   BB      99.0    1           1               BB          BB          55.0    0.0     55              55.0   */      /**************************************************************   SQL Server 2014 新增的函数   ***************************************************************/      --貌似没有什么      /**************************************************************   SQL Server 2016 新增的函数   ***************************************************************/      --  STRING_SPLIT ( string , separator ) #字符分割   SELECT value FROM STRING_SPLIT('A,B,C',',')   /*结果:   value   -----   A   B   C   */      --  STRING_ESCAPE( text , type )  #特殊字符转成带有转义字符的文本(type只支持json)   SELECT STRING_ESCAPE('   /  \    "     ', 'json') AS escapedText;   --结果:\   /  \\    "              --  DATEDIFF_BIG ( datepart , startdate , enddate ) #日期之间的计数   SELECT DATEDIFF(day, '2005-12-12', '2017-10-10'); --以前版本   SELECT DATEDIFF_BIG(day, '2005-12-12', '2017-10-10');   SELECT DATEDIFF_BIG(millisecond, '2005-12-31 23:59:59.9999999', '2006-01-01 00:00:00.0000000');   /*结果:   4320   4320   1   */      --  inputdate AT TIME ZONE timezone  #时区时间   SELECT * FROM sys.time_zone_info -- 时区及名称参考   SELECT CONVERT(DATETIME,'2017-10-10') AT TIME ZONE 'Pacific Standard Time'   SELECT CONVERT(DATETIME,'2017-10-10') AT TIME ZONE 'China Standard Time'   SELECT CONVERT(datetime2(0), '2017-10-10T01:01:00', 126) AT TIME ZONE 'Pacific Standard Time';   SELECT CONVERT(datetime2(0), '2017-10-10T01:01:00', 126) AT TIME ZONE 'China Standard Time';   /*结果:   2017-10-10 00:00:00.000 -07:00   2017-10-10 00:00:00.000 +08:00   2017-10-10 01:01:00 -07:00   2017-10-10 01:01:00 +08:00   */      --  COMPRESS ( expression ) # GZIP算法压缩为varbinary(max)   DECLARE @COM varbinary(max)   SELECT @COM = COMPRESS(N'{"sport":"Tennis","age": 28,"rank":1,"points":15258, turn":17}')   SELECT @COM   --结果:0x1F8B08000000000004002DCC410A80300C44D17F94D2B51B85A2780E2FE042A414AAD4BA12EFEE……(略)      --  DECOMPRESS ( expression )#解压缩   SELECT CAST(DECOMPRESS(@COM) AS NVARCHAR(MAX))   --结果:{"sport":"Tennis","age": 28,"rank":1,"points":15258, turn":17}         --  SESSION_CONTEXT(N'key')  #获取指定的键的值   EXEC sp_set_session_context 'user_id', 4;  --设置键值   SELECT SESSION_CONTEXT(N'user_id');     --结果:4         --  ISJSON ( expression ) #测试字符串是否包含有效JSON   DECLARE @param1 NVARCHAR(MAX)   DECLARE @param2 NVARCHAR(MAX)   SET @param1 = N' "id" : 2,"info": { "name": "John", "surname": "Smith" }, "age": 25 '     SET @param2 = N'[{ "id" : 2,"info": { "name": "John", "surname": "Smith" }, "age": 25 }]'     SELECT ISJSON(@param1) as P1, ISJSON(@param2) as P2   GO   /*结果:   P1  P2   --  --   0   1   */      --  JSON_VALUE ( expression , path ) #从 JSON 字符串中提取值   DECLARE @param NVARCHAR(MAX)   SET @param = N'{ "id" : 2,"info": { "name": "John", "surname": "Smith" }, "age": 25 }'     SELECT JSON_VALUE(@param,'$.id') as P1,JSON_VALUE(@param,'$.info.name')as P2   GO   /*结果:   P1  P2   --  ----   2   John   */      --  JSON_QUERY ( expression [ , path ] )  #从 JSON 字符串中提取对象或数组   DECLARE @param NVARCHAR(MAX)   SET @param = N'{ "id" : 2,"info": { "name": "John", "surname": "Smith" }, "age": 25 }'     SELECT JSON_QUERY(@param,'$.info')   GO   --结果:{ "name": "John", "surname": "Smith" }         --  JSON_MODIFY ( expression , path , newValue )  #更新的 JSON 字符串中属性的值并返回更新的 JSON 字符串   DECLARE @param NVARCHAR(MAX)   SET @param = N'{ "id" : 2,"info": { "name": "John", "surname": "Smith" }, "age": 25 }'     SELECT JSON_MODIFY(@param,'$.info.surname','newValue')   GO   --结果:{ "id" : 2,"info": { "name": "John", "surname": "newValue" }, "age": 25 }            /**************************************************************   SQL Server 2017 新增的函数   ***************************************************************/      --  CONCAT_WS ( separator, argument1, argument1 [, argumentN]… ) #按第一个分隔符连接后面的字符   SELECT CONCAT_WS( ' - ', 1, 'kk', '12dd')   --结果:1 - kk - 12dd      --  TRANSLATE ( inputString, characters, translations) #整体对应替换   SELECT TRANSLATE('2*[3+4]/{7-2}', '[]{}', '()()');   SELECT REPLACE(REPLACE(REPLACE(REPLACE('2*[3+4]/{7-2}','[','('), ']', ')'), '{', '('), '}', ')');   SELECT TRANSLATE('2*[3+4]/[7-2]', '[2', '61');   /*结果:   2*(3+4)/(7-2)   2*(3+4)/(7-2)   1*63+4]/67-1]   */      --  TRIM ( [ characters FROM ] string ) #删除字符串左右空格字符   SELECT TRIM( '     test    ') AS Result,LTRIM(RTRIM('     test    '))      --  STRING_AGG ( expression, separator ) #同列字符相连成一行   SELECT STRING_AGG (MyName, CHAR(13))  FROM (VALUES('AAAA'),('BBBBB'),('CCCCCC') )AS T(MyName)   SELECT STRING_AGG (MyName,',') FROM (VALUES('AAAA'),('BBBBB'),('CCCCCC') )AS T(MyName)   SELECT STRING_AGG (MyName,',') WITHIN GROUP(ORDER BY id DESC ) FROM (VALUES(1,'AAAA'),(1,'BBBBB'),(2,'CCCCCC'))AS T(id,MyName)   /*结果:   AAAA BBBBB CCCCCC   AAAA,BBBBB,CCCCCC   CCCCCC,BBBBB,AAAA   */

    时间:2019-07-09 关键词: sql server

  • 针对机器人和物联网应用,微软发布了Windows Server IoT 2019

    针对机器人和物联网应用,微软发布了Windows Server IoT 2019

    作为科技领域的老大哥,微软很多时候都有自己独特的选择。例如,2015年3月,在Windows 10系统中引入一个Windows IoT版本(物联网版本);例如,2018年9月,在Windows 10系统中再次引入Windows 10 ROS1版本(机器人版本);又如,2019年2月,发布Windows Server IoT 2019。据了解,针对今年2月的更新,微软Windows IoT和网络项目管理总监David Lemson给出的解释是,“通过使用Windows Server IoT 2019,设备制造商可以构建服务器级IoT边缘设备,实现高容量存储和计算方案,并在云端和边缘之间无缝扩展。”简言之,针对物联网,能力从云端继续向边缘侧拓展;针对机器人,再次强调其Windows 10 ROS1版本及功能。具体功能,David Lemson解释如下:Windows Azure物联网边缘。开发者可以很容易地将云端的工作负载带到边缘,从而充分利用Windows 10物联网平台的能力。托管服务通过在跨平台物联网设备上直接部署和运行AI、Azure服务和定制逻辑在本地交付云智能,通过使用这种托管,客户可以服务跨云或边缘扩展测试物联网解决方案,从而通过在边缘部署云应用程序和云服务来获益,同时确保它们满足延迟、带宽和数据隐私要求。Azure物联网设备代理。对于Windows某些跨行业客户,当物联网设备在现场或工厂车间时,直接访问设备并不总是可行的。Microsoft Azure IoT设备代理允许操作人员在Azure仪表板上远程配置、监视和管理他们的设备。Windows操作系统的机器人操作系统。将ROS引入到Windows IoT(即Windows 10 ROS1)可以实现丰富的AI和边缘AI功能,包括硬件加速的Windows机器学习、计算机视觉、Azure认知服务,以及到Azure物联网云服务的交钥匙连接。值得注意的是,据微软官网信息显示,Windows Server IoT 2019仅能通过拥有特殊专用权限的OEM渠道获得许可。Windows Server IoT 2019依旧分为Windows 10 IoT Core和Windows 10 IoT Enterprise两个版本,关于二者主要区别,微软也给出了相应的对比:在合作方面,微软表示,继续与NXP合作,在i.MX 8M和i.MX 8M Mini处理器上可以运行Windows 10 IoT Core版本;继续与高通合作,在高通骁龙系列处理器上可以运行Windows 10 IoT Enterprise版本。

    时间:2019-03-13 关键词: Windows 物联网 机器人 IoT 2019 server

  • 微软发布Windows Server IoT 2019,这次变化有点大!

    微软发布Windows Server IoT 2019,这次变化有点大!

    作为科技领域的老大哥,微软很多时候都有自己独特的选择。例如,2015年3月,在Windows 10系统中引入一个Windows IoT版本(物联网版本);例如,2018年9月,在Windows 10系统中再次引入Windows 10 ROS1版本(机器人版本);又如,2019年2月,发布Windows Server IoT 2019。据了解,针对今年2月的更新,微软Windows IoT和网络项目管理总监David Lemson给出的解释是,“通过使用Windows Server IoT 2019,设备制造商可以构建服务器级IoT边缘设备,实现高容量存储和计算方案,并在云端和边缘之间无缝扩展。”简言之,针对物联网,能力从云端继续向边缘侧拓展;针对机器人,再次强调其Windows 10 ROS1版本及功能。具体功能,David Lemson解释如下:Windows Azure物联网边缘。开发者可以很容易地将云端的工作负载带到边缘,从而充分利用Windows 10物联网平台的能力。托管服务通过在跨平台物联网设备上直接部署和运行AI、Azure服务和定制逻辑在本地交付云智能,通过使用这种托管,客户可以服务跨云或边缘扩展测试物联网解决方案,从而通过在边缘部署云应用程序和云服务来获益,同时确保它们满足延迟、带宽和数据隐私要求。Azure物联网设备代理。对于Windows某些跨行业客户,当物联网设备在现场或工厂车间时,直接访问设备并不总是可行的。Microsoft Azure IoT设备代理允许操作人员在Azure仪表板上远程配置、监视和管理他们的设备。Windows操作系统的机器人操作系统。将ROS引入到Windows IoT(即Windows 10 ROS1)可以实现丰富的AI和边缘AI功能,包括硬件加速的Windows机器学习、计算机视觉、Azure认知服务,以及到Azure物联网云服务的交钥匙连接。值得注意的是,据微软官网信息显示,Windows Server IoT 2019仅能通过拥有特殊专用权限的OEM渠道获得许可。Windows Server IoT 2019依旧分为Windows 10 IoT Core和Windows 10 IoT Enterprise两个版本,关于二者主要区别,微软也给出了相应的对比:在合作方面,微软表示,继续与NXP合作,在i.MX 8M和i.MX 8M Mini处理器上可以运行Windows 10 IoT Core版本;继续与高通合作,在高通骁龙系列处理器上可以运行Windows 10 IoT Enterprise版本。

    时间:2019-03-12 关键词: Windows 微软 物联网 机器人 IoT 2019 server

  • 避免端口劫持问题,可以这么做!

    避免端口劫持问题,可以这么做!

    最近使用TCP server时,发现如果监控INADDR_ANY地址也就是0.0.0.0后,如果使用本机ip再去监控同样的端口,一样可以监控成功。比如我的本机地址为10.254.1.100,我监控0.0.0.0 1200端口  ,再启动一个服务器10.254.1.100 1200端口,数据都会到10.254.1.100 1200这里去,如果关闭掉10.254.1.100 1200,则数据会到0.0.0.0 1200。这个在服务器上会导致很多意想不到的结果,相当于端口被劫持了一样,并且对调试也相当不利。通过设置SO_REUSEADDR可以解决这个问题。//独占当前端口,防止多网卡情况下端口被重复使用,导致出现不可预知的情况 //不允许同一个端口在不同IP下重复监控 char opt = 0; setsockopt(sockSvr, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt)); //SO_REUSEADDR 为true 就是允许在相同的端口不同的IP地址上创建套接描述字。以下是我的多网卡测试的例子SOCKET sockSvr = WSASocket(AF_INET, SOCK_STREAM, 0, 0, 0, WSA_FLAG_OVERLAPPED); if(INVALID_SOCKET == sockSvr) { WSACleanup(); return IOCP_SOCKET_ERROR; } //独占当前端口,防止多网卡情况下端口被重复使用,导致出现不可预知的情况 //不允许同一个端口在不同IP下重复监控 char opt = 0; setsockopt(sockSvr, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt)); //SO_REUSEADDR 为true 就是允许在相同的端口不同的IP地址上创建套接描述字。 SOCKADDR_IN addrSvr; ZeroMemory(&addrSvr, sizeof(SOCKADDR_IN)); addrSvr.sin_family = AF_INET; addrSvr.sin_port = htons(port); addrSvr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); int nRet = bind(sockSvr, (SOCKADDR*)&addrSvr, sizeof(SOCKADDR)); if(SOCKET_ERROR == nRet) { WSACleanup(); return IOCP_BIND_ERROR; } nRet = listen(sockSvr, MaxListen);//500:max number of connect request if(SOCKET_ERROR == nRet) { WSACleanup(); return IOCP_LISTEN_ERROR; }不管从哪个网卡来的连接都可以接入到本端口,这样服务器就不用管当前监控的IP地址了,也不会出现端口劫持问题了。

    时间:2019-03-06 关键词: socket 端口劫持 server

  • SQL Server数据库学习之 -- 常用语句二

    -- 引用数据库 USE [School01] GO SET ANSI_NULLS ON  -- 设置编码格式 GO SET QUOTED_IDENTIFIER ON GO -- 创建学生表 tb_student CREATE TABLE tb_student ( Sno CHAR(3) PRIMARY KEY NOT NULL, Sname CHAR(8) NOT NULL, Ssex CHAR(2) NOT NULL, Sbirthday DATETIME, Class CHAR(5) ) GO -- 创建教师表  tb_teacher CREATE TABLE tb_teacher ( Tno char(3) PRIMARY KEY NOT NULL, Tname char(4) NOT NULL, Tsex char(2) NOT NULL, Tbirthday datetime, Profession char(6), Depart varchar(10) NOT NULL ) GO -- 创建课程表 tb_course CREATE TABLE tb_course ( Cno char(5) PRIMARY KEY NOT NULL, Cname varchar(10) NOT NULL, Tno char(3) NOT NULL, FOREIGN KEY (Tno) REFERENCES tb_teacher(Tno)  -- 外键约束 ) GO CREATE TABLE tb_score  ( Sno char(3) NOT NULL,  Cno char(5) NOT NULL, Degree Decimal(4,1), FOREIGN KEY (Sno) REFERENCES tb_student(Sno),  -- 外键约束 FOREIGN KEY (Cno) REFERENCES tb_course(Cno)  -- 外键约束  )

    时间:2019-01-24 关键词: sql sql语句 server

  • sqlserver update或者Delete误操作恢复方法---【验证】

    经验教训:1、新建数据库一定要做一次全备份;2、制定定时计划任务做数据备份;3、决不能直接把开发环境连接生产数据库;4、做技术,尤其是做数据相关的技术,是要很严谨的,决不能掉以轻心,时时刻刻保持严谨之心; 灾难情况概述:在执行Update语句的时候,忘记添加Where条件,没有用事务,导致3000多条重要数据被我搞成一个模样。真是脑袋一热啊,一个按钮点下去全完蛋,而且之前还不备份。灾难应急过程:当时慌了神,但咬着牙告诉自己要冷静,脑海里n多后果浮想联翩,首先使用关键词“sqlserver update 误操作恢复”百度一顿搜,没有方案,很多人说没有备份不能恢复;然后相同关键词搜谷歌,也没有;最后加了个sql QQ群,点了几个管理员一通问,有两个回答的,其中一个说没有备份不行,另一个说使用日志可以恢复。然后,我改变关键词sqlserver日志还原恢复,结果看到了这个救命的文章,新建测试数据库,按照步骤走了一遍果然OK,然后把生产数据库数据文件和日志文件,以及3个月前的一个完整数据库备份拷贝到另一台电脑上,进行附加,然后按照原文步骤进行还原,果然,我的数据回来了!!!整个过程历时四个小时,太漫长了,那么多人都说不可以,但有一线希望我们决不放弃,如果我放弃了,命运可能就此变化了!关键点总结使用原文方法需要满足以下条件,原文博主也说的很清楚了,我再叙述一遍:1、数据库恢复模式为完整,不是的改过来;2、曾经完整备份过数据库,这一点我是11月14号发生的这件事,找到了7月30号的一个完整备份(.bak文件)具体操作步骤,请查看原文,请坚定的按照步骤走下去,过程中可能会因为操作不当或者其他原因,有些错误提示,记住可以采取删掉重新附加、关掉管理环境重新打开等方式。原文:http://blog.csdn.net/dba_huangzj/article/details/8491327再次感谢原文作者:發糞塗牆以及QQ朋友 :风扬/浅尾,希望这种有价值,有巨大意义的好文章越来越多。 PS:从鬼门关走了一圈回来(重要数据update误操作,非常重要),现在心里还不能平静,写一篇文章,记录一下这个莫大的教训,此次多亏一篇文章救急,非常感谢其作者,本博客也是对原文方法的一个验证(原文地址:http://blog.csdn.net/dba_huangzj/article/details/8491327,以下简称原文),再次表达原文作者的感激之情(如果没有这篇文章,我想我真的得卷铺盖走人了,情况可能会更糟!)。

    时间:2019-01-24 关键词: sql 数据备份 server

  • 存储过程中使用事务与try catch

    一、存储过程中使用事务的简单语法       在存储过程中使用事务时非常重要的,使用数据可以保持数据的关联完整性,在Sql server存储过程中使用事务也很简单,用一个例子来说明它的语法格式: 代码 : Create Procedure MyProcedure ( @Param1 nvarchar(10), @param2 nvarchar(10) ) AS Begin Set NOCOUNT ON; Set XACT_ABORT ON; Begin Tran Delete from table1 where name=’abc’; Insert into table2 values(value1,value2,value3); Commit Tran End           说明:1 、使用存储过程执行事物,需要开启XACT_ABORT参数(默认值为Off),将该参数设置为On,表示当执行事务时,如果出错,会将 transcation设置为uncommittable状态,那么在语句块批处理结束后将回滚所有操作;如果该参数设置为Off,表示当执行事务时,如果出错,出错的语句将不会执行,其他正确的操作继续执行。 2、当SET NOCOUNT 为 ON 时,不返回计数(计数表示受 Transact-SQL 语句影响的行数,例如在Sql server查询分析器中执行一个delete操作后,下方窗口会提示(3)Rows Affected)。当   SET NOCOUNT 为 OFF 时,返回计数,我们应该在存储过程的头部加上SET NOCOUNT ON 这样的话,在退出存储过程的时候加上 SET NOCOUNT OFF这样的话,以达到优化存储过程的目的。   二、事务内设置保存点   用户可以在事务内设置保存点或标记。保存点定义如果有条件地取消事务的一部分,事务可以返回的位置。如果将事务回滚到保存点,则必须(如果需要,使用更多的 Transact-SQL 语句和 COMMIT TRANSACTION 语句)继续完成事务,或者必须(通过将事务回滚到其起始点)完全取消事务。若要取消整个事务,请使用 ROLLBACK TRANSACTION transaction_name 格式。这将撤消事务的所有语句和过程。如: 代码 Create Procedure MyProcedure AS Begin Set NOCOUNT ON; Set XACT_ABORT ON; begin tran ok --开始一个事务OK delete from rxqz where qz= 'rx015 ' --删除数据 save tran bcd --保存一个事务点命名为bcd update sz set name='李丽s' where name= '李丽'--修改数据if @@error0 --判断修改数据有没有出错 begin --如果出错 rollback tran bcd -- 回滚事务到BCD 的还原点 commit tran ok --提交事务 endelse --没有出错 commit tran ok --提交事务 End       说明:1、@@error判断是否有错误,为0表示没有错误,但是对那种重大错误无法捕捉,而且@@error只能前一句sql语句生效。   三、存储过程使用try…catch捕获错误   在存储过程中可以使用try…catch语句来捕获错误,如下:   代码 Create Procedure MyProcedure ( @Param1 nvarchar(10), @param2 nvarchar(10) ) AS Begin Set NOCOUNT ON; Begin try Delete from table1 where name=’abc’; Insert into table2 values(value1,value2,value3); End try Begin Catch SELECT ERROR_NUMBER() AS ErrorNumber, ERROR_MESSAGE() AS ErrorMessage; End Catch End       说明:1、捕获错误的函数有很多,如下:            ERROR_NUMBER() 返回错误号。     ERROR_SEVERITY() 返回严重性。     ERROR_STATE() 返回错误状态号。     ERROR_PROCEDURE() 返回出现错误的存储过程或触发器的名称。     ERROR_LINE() 返回导致错误的例程中的行号。     ERROR_MESSAGE() 返回错误消息的完整文本。该文本可包括任何可替换参数所提供的值,如长度、对象名或时间。     2、有些错误,如sql语句中的表名称输入错误,这是数据库引擎无法解析这个表名称时,所发生的错误在当前的try…catch语句中无法捕获,必须由外层调用该存储过程的地方使用                           try…catch来进行捕获。   四、存储过程中事务和try…catch联合使用   在存储过程中使用事务时,如果没有try…catch语句,那么当set xact_abort on时,如果有错误发生,在批处理语句结束后,系统会自动回滚所有的sql操作。当set xact_abort off时,如果有错误发生,在批处理语句结束后,系统会执行所有没有发生错误的语句,发生错误的语句将不会被执行。 在存储过程中使用事务时,如果存在try…catch语句块,那么当捕获到错误时,需要在catch语句块中手动进行Rollback操作,否则系统会给客户端传递一条错误信息。如果在存储过程开始处将set xact_abort on,那么当有错误发生时,系统会将当前事务置为不可提交状态,即会将xact_state()置为-1,此时只可以对事务进行Rollback操作,不可进行提交(commit)操作,那么我们在catch语句块中就可以根据xact_state()的值来判断是否有事务处于不可提交状态,如果有则可以进行rollback操作了。如果在存储过程开始处将set xact_abort off,那么当有错误发生时,系统不会讲xact_state()置为-1,那么我们在catch块中就不可以根据该函数值来判断是否需要进行 rollback了,但是我们可以根据@@Trancount全局变量来判断,如果在catch块中判断出@@Trancount数值大于0,代表还有未提交的事务,既然进入catch语句块了,那么还存在未提交的事务,该事务应该是需要rollback的,但是这种方法在某些情况下可能判断的不准确。推荐的方法还是将set xact_abort on,然后在catch中判断xact_state()的值来判断是否需要Rollback操作。 下面我们来看看两个例子: 一.使用Set xact_abort       on  代码 Create proc myProcedure As beginset xact_abort on; begin try begin tran insert into TestStu values('Terry','boy',23); insert into TestStu values('Mary','girl',21); commit tran end try begin catch--在此可以使用xact_state()来判断是否有不可提交的事务,不可提交的事务--表示在事务内部发生错误了。Xact_state()有三种值:-1.事务不可提交;--1.事务可提交;0.表示没有事务,此时commit或者rollback会报错。if xact_state()=-1 rollback tran; end catch end       二.使用Set xact_abort off   代码 Create proc myProcedure As beginset xact_abort off; begin try begin tran insert into TestStu values('Terry','boy',23); insert into TestStu values('Mary','girl',21); commit tran end try begin catch--在此不可以使用xact_state来判断是否有不可提交的事务--只可以使用@@Trancount来判断是否有还未提交的事务,未提交的事务未必--就是不可提交的事务,所以使用@@TranCount>0后就RollBack是不准确的if @@TranCount>0 rollback tran; end catch end        另外,对于@@Trancount需要说明的是,begin  tran 语句将 @@Trancount加 1。Rollback  tran将 @@Trancount递减到 0,但 Rollback tran savepoint_name 除外,它不影响 @@Trancount。Commit  tran 或 Commit  work 将 @@Trancount 递减 1。   转载:http://blog.sina.com.cn/s/blog_6f7c75ad0100uqcy.html

    时间:2019-01-24 关键词: 存储过程 sql server

  • SQL Server中使用表类型参数批量添加和修改的存储过程

    SQL Server中使用表类型参数批量添加和修改的存储过程

    摘要:    最近做项目中遇到批量添加和修改的问题,在老大的指导下学会了使用表类型参数来做批量操作。为了巩固强化,围绕这个技术又做了个小demo。开始正题:       首先,我们在SQL Server 2008下创建一个示例数据库名为TableTypeTest,再在该数据库下创建一个名为Class和Student的表,结构如下:              再在TableTypeTest数据库下创建一个自定义表类型,取名StudentType,如下:CREATE TYPE [dbo].[StudentType] AS TABLE(     [SID] [int] NOT NULL,     [CID] [int] NOT NULL,     [SName] [nvarchar](50) NOT NULL ) GO然后,创建两个存储过程,批量添加和批量修改,分别为InserNewStudent和UpdateStudent,如下InserNewStudent:CREATE PROCEDURE [dbo].[InserNewStudent]      @Dt dbo.StudentType readonly AS BEGIN     insert into dbo.Student(CID,SName) select t.CID,t.SName  from @Dt as t  END GOUpdateStudent:启动Visual Studio 2010,创建一个默认的窗体应用程序,窗体用于显示所有班级列表,操作每个班级下的学生通过选中该班级,然后右键操作。如下:创建显示班级下的所有学生列表窗体,如下:创建批量添加学生的窗体,如下:关键代码如下:////// 批量添加          ///public static bool AddBantch(DataTable dt) {              string pName = "dbo.InserNewStudent";              ListpList = new List() {              DbHelper.CreateSqlParemeterStructured("@Dt",dt)              };              try              {                  DbHelper.RunProcedure(pName, pList);                  return true;              }              catch              {                  return false;              }          }private void button1_Click(object sender, EventArgs e)         {             if (string.IsNullOrEmpty(this.textBox1.Text) || string.IsNullOrEmpty(this.textBox4.Text) || string.IsNullOrEmpty(this.textBox6.Text))             {                 MessageBox.Show("不能有空文本框");             }             else {                 DataTable dt = new DataTable();                 dt.Columns.Add("SID");                 dt.Columns.Add("CID");                 dt.Columns.Add("SName");                 DataRow dr;                 dr = dt.NewRow();                 dr["SID"] = 0;//此列虽然在添加的时候无用,但必须赋值,否则报错                 dr["CID"] = CID;                 dr["SName"] = this.textBox1.Text;                 dt.Rows.Add(dr);                 dr = dt.NewRow();                 dr["SID"] = 0;                 dr["CID"] = CID;                 dr["SName"] = this.textBox4.Text;                 dt.Rows.Add(dr);                 dr = dt.NewRow();                 dr["SID"] = 0;                 dr["CID"] = CID;                 dr["SName"] = this.textBox6.Text;                 dt.Rows.Add(dr);                 if (Library.AddBantch(dt))                 {                     MessageBox.Show("批量添加成功!");                     this.Close();                 }                 else                 {                     MessageBox.Show("批量添加失败!");                     this.Close();                 }             }         } 创建批量更改班级学生姓名的窗体,如下:关键代码如下:////// 批量修改          ///public static bool UpdateBantch(DataTable dt) {              string pName = "dbo.UpdateStudent";              ListpList = new List() {               DbHelper.CreateSqlParemeterStructured("@Dt",dt)              };              try              {                  DbHelper.RunProcedure(pName, pList);                  return true;              }              catch               {                  return false;              }          }private void button1_Click(object sender, EventArgs e)         {             int rows = this.dataGridView1.Rows.Count;             DataTable dt = new DataTable();             dt.Columns.Add("SID");             dt.Columns.Add("CID");             dt.Columns.Add("SName");             DataRow dr;             for (int i = 0; i < rows;i++ ) {             DataGridViewRow dtr=this.dataGridView1.Rows[i];             dr = dt.NewRow();             dr["SID"] = dtr.Cells[0].Value;             dr["CID"] = dtr.Cells[1].Value;             dr["SName"] = dtr.Cells[2].Value;             dt.Rows.Add(dr);             }             if (Library.UpdateBantch(dt))             {                 MessageBox.Show("批量更改成功!");             }             else {                 MessageBox.Show("批量更改失败!");             }         }源码下载PS:数据库连接要在程序中的App.Config中配置

    时间:2019-01-24 关键词: 存储 sql server

  • SQL Server常用快捷键

    一、“文本操作”快捷键 1、Ctrl + K,Ctrl + C:注释选定内容2、Ctrl + K,Ctrl + U:取消注释选定内容3、Ctrl + K,Ctrl + :删除水平空白4、Tab:增大缩进5、SHIFT+TAB:减小缩进6、Ctrl + Enter:在光标之上插入一个空行 (不论光标在一行的何处) 7、Ctrl + Shift + Enter:在光标之下插入一个空行 (这样就不用先将光标移到行首或行尾了)8、Shift + Alt + T:将包含插入点的行移动到下一行之下。(可以看做是两行交换)9、Ctrl + U:转换为小写10、CTRL+SHIFT+L:将选定文本更改为小写字符11、Ctrl + Shift + U:将选定文本更改为大写字符 12、Ctrl + Delete:删除插入点右侧的紧挨的单词13、Ctrl + Backspace:删除插入点左侧的紧挨的单词14、Ctrl + Shift + T:对调插入点两边的单词。例如,main int 将更改为 int main  二、“调试”快捷键 1、CTRL + B:显示“断点”对话框,在此可添加和修改断点。2、CTRL + SHIFT + F9:清除项目中的所有断点3、CTRL + F9 :在当前行上设置断点4、CTRL + ALT + I:显示“即时”窗口,在该窗口中可以计算表达式并执行单个的命令。5、CTRL + ALT + L:显示“局部变量”窗口,以查看当前堆栈帧中每个过程的变量及其值。 6、CTRL + SHIFT + R:显示“进程”对话框,该对话框允许在单个解决方案中同时调试多个程序。7、CTRL + SHIFT + F5:终止调试会话,重新生成,然后从开始处开始运行应用程序。可用于“中断”模式和“运行”模式。8、F11:在执行进入函数调用后,逐条语句执行代码,即单步执行9、SHIFT + F11:执行当前执行点所处函数的剩余行10、F10:执行下一行代码,但不执行任何函数调用  三、“搜索和替换”快捷键 1、CTRL + F:显示“查找”对话框。2、F3:查找上次搜索文本的下一个匹配项3、CTRL + H:显示“替换”对话框4、ALT + F3,S:暂停当前的“在文件中查找”操作 参考资料: SQL Server常用快捷键 http://www.studyofnet.com/news/1230.html

    时间:2019-01-24 关键词: sql 快捷键 server

  • 根事务要确认,但事务中止了操作—解决办法

    根事务要确认,但事务中止了操作—解决办法 SQL 报如上的错误:是因为 没有使用 SET XACT_ABORT ON begin tran/***/commit tran 之前使用了 SET XACT_ABORT ON 才能回滚  ----------------------------当 SET XACT_ABORT 为 ON 时,如果 Transact-SQL 语句产生运行时错误,整个事务将终止并回滚。为 OFF 时,只回滚产生错误的 Transact-SQL 语句,而事务将继续进行处理。编译错误(如语法错误)不受 SET XACT_ABORT 的影响。对于大多数 OLE DB 提供程序(包括 SQL Server),隐性或显式事务中的数据修改语句必须将 XACT_ABORT 设置为 ON。唯一不需要该选项的情况是提供程序支持嵌套事务时。有关更多信息,请参见分布式查询和分布式事务。SET XACT_ABORT 的设置是在执行或运行时设置,而不是在分析时设置。

    时间:2019-01-24 关键词: 存储过程 sql server

首页  上一页  1 2 3 4 5 6 7 下一页 尾页
发布文章

技术子站

更多

项目外包