精华内容
下载资源
问答
  • 发送的数据是0x21。0b0010,0001 刚开始一个拉低,代表数据开始传输。 然后先发送低位,后发送高位。111101000,01001111111

     

    发送的数据是0x21。0b0010,0001

    刚开始一个拉低,代表数据开始传输。

    然后先发送低位,后发送高位。111101000,01001111111

    展开全文
  • 网络数据包发送接收全过程

    千次阅读 2016-04-14 16:38:53
    Linux的网络接口分为四部分:网络设备接口,网络接口核心,网络协议族,网络接口socket层。 可参考: ... 网络接口核心部分是整个网络接口的关键部位,它为网络协议提供统一的发送接口,屏蔽各种各样

    Linux的网络接口分为四部分:网络设备接口,网络接口核心,网络协议族,网络接口socket层。
    可参考:
    http://lxr.linux.no/linux+v2.6.30.4/net/
      网络设备接口部分主要负责从物理介质接收和发送数据,实现的文件在linu/driver/net目录下面。

      网络接口核心部分是整个网络接口的关键部位,它为网络协议提供统一的发送接口,屏蔽各种各样的物理介质,同时有负责把来自下层的包向合适的协议配送。它是网络接口的中枢部份。它的主要实现文件在linux/net/core目录下,其中linux/net/core/dev.c为主要管理文件。

      网络协议族部分是各种具体协议实现的部份。Linux支持TCP/IP,IPX,X.25,AppleTalk等的协议,各种具体协议实现的源码在linux/net/目录下相应的名称。在这里主要讨论TCP/IP(IPv4)协议,实现的源码在linux/net/ipv4,其中linux/net/ipv4/af_inet.c是主要的管理文件。

      网络接口Socket层为用户提供的网络服务的编程接口,主要的源码在linux/net/socket.c

    发送:

    应用程序调用系统调用,将数据发送给socket
    socket检查数据类型,调用相应的send函数
    send函数检查socket状态、协议类型,传给传输层
    tcp/udp(传输层协议)为这些数据创建数据结构,加入协议头部,比如端口号、检验和,传给下层(网络层)
    ip(网络层协议)添加ip头,比如ip地址、检验和
    如果数据包大小超过了mtu(最大数据包大小),则分片;ip将这些数据包传给链路层
    链路层写到网卡队列
    网卡调用响应中断驱动程序,发送到网络

    接收:

    数据包从网络到达网卡,网卡接收帧,放入网卡buffer,在向系统发送中断请求
    cpu调用相应中断函数,这些中断处理程序在网卡驱动中
    中断处理函数从网卡读入内存,交给链路层
    链路层将包放入自己的队列,置软中断标志位
    进程调度器看到了标志位,调度相应进程
    该进程将包从队列取出,与相应协议匹配,一般为ip协议,再将包传递给该协议接收函数
    ip层对包进行错误检测,无错,路由
    路由结果,packet被转发或者继续向上层传递
    如果发往本机,进入链路层
    链路层再进行错误侦测,查找相应端口关联socket,包被放入相应socket接收队列

    socket唤醒拥有该socket的进程,进程从系统调用read中返回,将数据拷贝到自己的buffer,返回用户态。


    DNS请求流程

    1、PC1要访问www.google.com,需要先知道对应IP地址。
    域名只起助记作用,互联网访问通过IP进行。
    比方,DNS是公民身份信息库,ip是身份证号,域名是该身份证号对应的人名。
    当然,这个比方不是很恰当,域名也必须唯一的,与ip对应。

    2、于是,PC1需要像DNS请求,查找www.google.com对应的ip,即发送dns请求:
    PC1查找dns,发现不在同一个网络,不同网段需要网关转发。
    但是,PC1需要先发送给网关,就需要先知道网关ip。
    网关用于连接不同网络,并且有自己的IP,PC1需要知道网关ip。于是,通过ARP请求,像内网广播网关ip,网关回复mac地址。
    PC1得到了网关的mac地址,将ip包封装到以太网帧,发送给网关。

    3、网关收到该以太网帧,需要转交给dns服务器。
    同样,网关可能需要发送ARP请求,得到dns的mac地址。

    4、dns服务器收到请求,将www.google.com的ip发送给网关,网关再根据NAT会话表项,将目的ip转换成PC1的,再发送给PC1(此过程可能同样需要ARP请求)。

    5、PC1收到了目的ip,再可以通过类似上面的方式发送请求(目的ip再可以直接填上获取的ip)。

    其中:
    ARP==>将ip广播,目的主机响应,反馈mac地址。


    NAT==>在一个网络内部,自定义合法的ip地址。内网各主机通过内网通讯;与外网通过NAT转换,变成外网合法ip。这样,将内网与外网隔离,各个网络有自己的ip,既可以重叠,又可以通过少数几个ip与外网通讯,在ip大量缺乏的现代,节省了很多。

    展开全文
  • USART发送数据

    千次阅读 2019-04-27 00:14:00
    一、USART简介 ...TX为发送数据的输出引脚,RX为接收数据的输入引脚,SCLK为发送器时钟输出引脚(同步模式下会用到)。其中SCLK来源于APB1总线时钟(36MHz)和APB2总线时钟(72MHz)。 这里涉及到USART数据...

    一、USART简介

    USART即为通用同步异步收发器,用于串行通信,例如其可以用于打印程序输出信息,以便于调试程序。

    USART框图

    图10-1

    这里简单介绍下USART框图。

    TX为发送数据的输出引脚,RX为接收数据的输入引脚,SCLK为发送器时钟输出引脚(同步模式下会用到)。其中SCLK来源于APB1总线时钟(36MHz)和APB2总线时钟(72MHz)。

    这里涉及到USART数据寄存器(USART_DR)。如图10-2。

    图10-2

    数据的发送和接收

    从图10-2的寄存器描述我们知道,USART_DR实际上包含了一个发送用的TDR寄存器,一个接收用的RDR寄存器。发送时,把TDR内容转移到发送移位寄存器,由发送移位寄存器一位一位发出;接收时,把收到的每一位保存到接收移位寄存器然后再转移到RDR。

    USART有专门的发送器和接收器,在使用USART前需要先使能USART,将USART_CR1寄存器的UE位置1即可。而发送或接收的数据字长可选8位或9位,由USART_CR1的M位控制。

    要启动数据发送,需要先使能USART_CR1的TE位,则发送移位寄存器的数据会在TX引脚输出,从低位开始发送,如果是同步模式,则SCLK也会输出时钟信号。在异步模式中,一个字符帧包含三部分:起始位+数据帧+停止位。中间部分的数据帧则是我们要发送的8位或9位数据。当使能TE位后,发送器开始会先发送一个空闲帧,然后往USART_DR写入要发送的数据。发送完成后,等待状态寄存器(USART_SR)的TC位置1后,则代表数据传输完成,同时如果USART_CR1的TCIE位置1,将产生中断。

    同理,在接收时,需要置位USART_CR1的RE位,使能接收。接收完成后,会把USART_SR的RXNE位置1,同时如果USART_CR1的RXNEIE位置1,可以产生中断。

    USART_DR、USART_SR和USART_CR1~3需要结合使用,相关寄存器描述可自行查阅参考手册。

    波特率相关

    USART中,波特率和比特率的值相等,所以一般不区分这两个概念。波特率越大,传输速率越快。USART的发送器和接收器使用相同的波特率,公式如下:

    boud =  f / (16*USARTDIV)

    其中boud为波特率的值,f为USART时钟频率,USARTDIV是USART分频器除法因子,如图10-3的寄存器描述。

    图10-3

     

    由描述可知,DIV_Mantissa为USARTDIV的整数部分,DIV_Fraction为USARTDIV的小数部分。那么,

    USARTDIV = DIV_Mantissa + DIV_Fraction / 16

    波特率的常用值有2400、9600、19200、115200。

    例如,挂载在APB2总线的USART1,其有72MHz的时钟频率,即f=72MHz,假设我们需要115200的波特率,则由上面的公式可得:

    115200 = 72000000 / (16*USARTDIV)

    我们能得到USARTDIV=39.0625,那么

    DIV_Mantissa=39=0x17,
    DIV_Fraction=0.625*16=1=0x01

    这时我们应该设置USART_BRR的值为0x171。

    校验控制

    USART还支持奇偶校验。当使用校验位时,数据帧长度为8位数据帧加上1位校验位,共9位,此时USART_CR1的M位需要置1。将USART_CR1的PCE位置1可以使能校验控制。奇偶校验由硬件自动完成,在发送数据时会自动添加校验位,接收数据时会自动验证校验位。接收数据验证校验位时如果校验失败,USART_SR的PE位将会置1,同时如果USART_CR1的PEIE位置1,便能产生奇偶校验中断。

    使能校验控制后,每个字符帧组成将变为:起始位+数据帧+校验位+停止位。

    二、使用USART发送数据

      我们在写单片机程序的时候,在Debug时,往往要用到串口输出信息,这是会使用printf打印出我们想要的信息来,但是printf有一个弊端,就是输出打印时间较长。这样在一些对时间精度要求非常高的场合,使用printf将会带来一系列问题,这时,如果使用单片机的USART自定义一个协议,直接发送数据到上位机,将会得到我们想要的效果。下面对怎样使用USART发送数据做一个整理。

    1、发送单个字符

    void USART1_PutChar(USART_TypeDef * USARTx,u8 ch){
        USART_SendData8(USARTx,(u8)ch);
        while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE)==RESET);
        while(USART_GetFlagStatus(USARTx,USART_FLAG_TC) == RESET);
    }

    2、发送固定长度的字符串

    void USART1_PutStrLen(USART_TypeDef * USARTx,u8 *buf,u16 len){
        for(;len > 0 ; len--) {
            USART_SendData8(USARTx,*buf++);    
            while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE) == RESET);
        }
        while(USART_GetFlagStatus(USARTx,USART_FLAG_TC) == RESET);
    }

    3、发送任意长度的字符串

    void USART1_PutStr(USART_TypeDef * USARTx,u8 *buf){
        while(*buf){
            USART_SendData8(USARTx,*buf++);
            while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE) == RESET);
            // 这句话有必要加,他是用于检查串口是否发送完成的标志,如果不加这句话会发生数据丢失的情况。
        }
        while(USART_GetFlagStatus(USARTx,USART_FLAG_TC) == RESET);
        // 这句话有必要加,他是用于检查串口是否发送完成的标志,如果不加这句话会发生数据丢失的情况。
    }

    4、 实时操作系统(考虑函数重入)

    该函数就可以像printf使用可变参数。通过观察函数但这个函数只支持了%d,%s的参数,想要支持更多,可以仿照printf的函数写法加以补充。

    void USART_printf ( USART_TypeDef * USARTx, char * Data, ... ){
    	const char *s;
    	int d;   
    	char buf[16];
    	
    	va_list ap;
    	va_start(ap, Data);
     
    	while ( * Data != 0 ){		  // 判断是否到达字符串结束符			                          
    		if ( * Data == 0x5c ){	  //'\'								  
    			switch ( *++Data ){
    				case 'r':		//回车符
    				    USART_SendData(USARTx, 0x0d);
    				    Data ++;
    				break;
     
    				case 'n':	    //换行符
    				    USART_SendData(USARTx, 0x0a);	
    				    Data ++;
    				break;
     
    				default:
    				    Data ++;
    				break;
    			}			 
    		}		
    		else if ( * Data == '%'){
    			switch ( *++Data )
    			{				
    				case 's'://字符串
    				    s = va_arg(ap, const char *);				
    				    for ( ; *s; s++) {
    					    USART_SendData(USARTx,*s);
    					    while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );
    				    }				
    				    Data++;				
    				break; 
    				case 'd'://十进制
    				    d = va_arg(ap, int);				
    				    itoa(d, buf, 10);				
    				    for (s = buf; *s; s++){
    					    USART_SendData(USARTx,*s);
    					    while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );
    				    }				
    				    Data++;				
    				break;				
    				default:
    				    Data++;				
    				break;				
    			}		 
    		}		
    		else 
                USART_SendData(USARTx, *Data++);		
    		while ( USART_GetFlagStatus ( USARTx, USART_FLAG_TXE ) == RESET );		
    	}
    }

    二、使用USART接收数据

    数据的头标识为“\n”既换行符,尾标识为“+”。该函数将串口接收的数据存放在USART_Buffer数组中,然后先判断当前字符是不是尾标识,如果是说明接收完毕,然后再来判断头标识是不是“+”号,如果还是那么就是我们想要的数据,接下来就可以进行相应数据的处理了。但如果不是那么就让Usart2_Rx=0重新接收数据。这样做的有以下好处:

    • 可以接受不定长度的数据,最大接收长度可以通过Max_BUFF_Len来更改
    • 可以接受指定的数据
    • 防止接收的数据使数组越界

            这里我的把接收正确数据直接打印出来,也可以通过设置标识位,然后在主函数里面轮询再操作。

    1、正常接收

    void USART2_IRQHandler(){
    	if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET){ //中断产生 	
    		USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志
    			 
    		Uart2_Buffer[Uart2_Rx] = USART_ReceiveData(USART2); //接收串口1数据到buff缓冲区
    		Uart2_Rx++; 
         		 
    		if(Uart2_Buffer[Uart2_Rx-1] == 0x0a || Uart2_Rx == Max_BUFF_Len){ //如果接收到尾标识是换行符(或者等于最大接受数就清空重新接收)		
    			if(Uart2_Buffer[0] == '+'){ //检测到头标识是我们需要的 			
    				printf("%s\r\n",Uart2_Buffer); //这里我做打印数据处理
    				Uart2_Rx=0;                                   
    			} 
    			else{
    				Uart2_Rx=0;//不是我们需要的数据或者达到最大接收数则开始重新接收
    			}
    		}
    	}
    }

    2、DMA接收

    串口空闲中断,一帧数据过来中断进入一次且接收的数据时候是DMA来搬运到指定缓冲区(程序中是USART1_RECEIVE_DMABuffer数组),不占用CPU时间。

    #define DMA_USART1_RECEIVE_LEN 18        //根据需要设置
    void USART1_IRQHandler(void){     
        u32 temp = 0;  
        uint16_t i = 0;  
          
        if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET){  
            USART1->SR;  
            USART1->DR; //这里我们通过先读SR(状态寄存器)和DR(数据寄存器)来清USART_IT_IDLE标志 			
            DMA_Cmd(DMA1_Channel5,DISABLE);  
            temp = DMA_USART1_RECEIVE_LEN - DMA_GetCurrDataCounter(DMA1_Channel5); //接收的字符串长度=设置的接收长度-剩余DMA缓存大小 
            for (i = 0;i < temp;i++){  
                Uart2_Buffer[i] = USART1_RECEIVE_DMABuffer[i];
            }  
            //设置传输数据长度  
            DMA_SetCurrDataCounter(DMA1_Channel5,DMA_USART1_RECEIVE_LEN);  
            //打开DMA  
            DMA_Cmd(DMA1_Channel5,ENABLE);  
        }        
    }

     

     

     

     

     

     

     

     

     

     

     

    展开全文
  • TCP数据发送发送窗口

    千次阅读 2019-02-26 00:07:12
    TCP的发送过程由滑动窗口控制,而滑动窗口的大小受限于发送窗口和拥塞窗口,拥塞窗口由拥塞控制算法的代表,而发送窗口是流量控制算法的代表,这篇笔记记录了发送窗口相关的内容,包括发送窗口的初始化、更新、以及...

    TCP的发送过程由滑动窗口控制,而滑动窗口的大小受限于发送窗口和拥塞窗口,拥塞窗口由拥塞控制算法的代表,而发送窗口是流量控制算法的代表,这篇笔记记录了发送窗口相关的内容,包括发送窗口的初始化、更新、以及它是如何影响数据发送过程的。

    1. 概述

    TCP的发送窗口可以用下图表示:
    在这里插入图片描述

    如图所示,TCB中有三个成员和发送窗口强相关。

    struct tcp_sock {
    ...
    	//下一个要发送的序号,即序号等于snd_nxt的数据还没有发送
    	u32	snd_nxt;	/* Next sequence we send		*/
    	//已经发送,但是还没有被确认的最小序号,注意序号等于snd_una的数据已经发送,
    	//最想收到的确认号要大于snd_una。但是有一个特殊情况,如果发送的所有数据都
    	//已经被确认,那么snd_una将等于下一个要发送的数据,即snd_una代表的数据还
    	//没有发送,见下面tcp_ack()更新snd_una就可以理解这一点了
    	u32	snd_una;	/* First byte we want an ack for	*/
    	//发送窗口大小,以字节为单位,来源于输入段首部的窗口字段,即对端接收缓冲区的剩余大小
    	u32	snd_wnd;	/* The window we expect to receive	*/
    	//记录到目前为止对端通告过的窗口的最大值,可以代表对端接收缓冲区的最大值
    	u32	max_window;	/* Maximal window ever seen from peer	*/
    	//写系统调用一旦成功返回,说明数据一被TCP协议接收,这时就要为每一个数据分配一个序号,
    	//write_seq就是下一个要分配的序号,其初始值由secure_tcp_sequence_number()基于
    	//算法生成。注意等于write_seq的序号还没有被分配
    	u32	write_seq;	/* Tail(+1) of data held in tcp send buffer */
    ...
    };
    

    2. snd_una和snd_wnd的更新

    snd_una是发送窗口的左边界,如果该字段更新,即使发送窗口大小snd_wnd没有发生变化,整个发送窗口也会前移,这样从流量控制的角度,就可以发送更多的数据(是否真的可以发送,还要考虑拥塞窗口等其它因素)。

    2.1 初始化

    可以想的到,snd_una的初始化一定发生在第一个数据段发送过程中,而snd_wnd的初始化应该是发生在第一个输入段处理过程中,所以需要客户端和服务器端分开来看。

    2.1.1 客户端初始化

    客户端对snd_una的初始化当然是发生在SYN段的发送过程中,相关代码如下:

    int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
    {
    ...
    	//选择初始发送序号
    	if (!tp->write_seq)
    		tp->write_seq = secure_tcp_sequence_number(inet->saddr,
    							   inet->daddr,
    							   inet->sport,
    							   usin->sin_port);
    ...
    }
    static void tcp_connect_init(struct sock *sk)
    {
    ...
    	//发送窗口大小要从输入段首部的窗口字段获取,这时还没有任何输入段,先初始化为0
    	tp->snd_wnd = 0;
    	//初始化snd_una为第一个序号,该函数之后write_seq将会分配给SYN段
    	tp->snd_una = tp->write_seq;
    ...
    }
    

    对snd_wnd的初始化发生在收到SYN+ACK段时,相关代码如下:

    static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
    					 struct tcphdr *th, unsigned len)
    {
    ...
    	if (th->ack) {
    ...
    		tp->snd_wnd = ntohs(th->window);
    ...
    	}
    }
    

    2.1.2 服务器端初始化

    正面理解的话,服务器端对snd_una的初始化应该是发生在发送SYN+ACK段时,但是实际上不是,而是发生在收到第三次握手的ACK段时。如笔记TCP之服务器端收到ACK包所述,三次握手完成后,创建了子套接字,然后在tcp_child_process()中会继续调用tcp_rcv_state_process()处理ACK报文,代码如下:

    int tcp_child_process(struct sock *parent, struct sock *child,
    		      struct sk_buff *skb)
    {
    	int ret = 0;
    	int state = child->sk_state;
    
    	//如果用户进程没有锁住child,则让child重新处理该ACK报文,这可以让child
    	//套接字由TCP_SYN_RECV迁移到TCP_ESTABLISH状态
    	if (!sock_owned_by_user(child)) {
    		//见下文
    		ret = tcp_rcv_state_process(child, skb, tcp_hdr(skb),
    					    skb->len);
    		/* Wakeup parent, send SIGIO */
    		//child套接字状态发生了迁移,唤醒监听套接字上的进程,可能由于调用accept()而block
    		if (state == TCP_SYN_RECV && child->sk_state != state)
    			parent->sk_data_ready(parent, 0);
    	} else {
    		/* Alas, it is possible again, because we do lookup
    		 * in main socket hash table and lock on listening
    		 * socket does not protect us more.
    		 */
    		 //缓存该skb后续处理
    		sk_add_backlog(child, skb);
    	}
    
    	bh_unlock_sock(child);
    	sock_put(child);
    	return ret;
    }
    
    int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
    			  struct tcphdr *th, unsigned len)
    {
    ...
    	/* step 5: check the ACK field */
    	if (th->ack) {
    		int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH);
    
    		switch (sk->sk_state) {
    		case TCP_SYN_RECV:
    			if (acceptable) {
    ...
    				tcp_set_state(sk, TCP_ESTABLISHED);
    				//用ACK段中的确认号初始化本端的snd_una
    				tp->snd_una = TCP_SKB_CB(skb)->ack_seq;
    				//用输入报文的窗口字段初始化发送窗口大小
    				tp->snd_wnd = ntohs(th->window) <<
    					      tp->rx_opt.snd_wscale;
    ...
    			}
    			break;
    ...
    		}//end of switch()
    	} else
    		goto discard;
    ...
    	return 0;
    }
    

    2.2 传输过程中更新

    显然,数据传输过程中,应该在收到ACK后更新snd_una和snd_wnd。如果输入段中携带了ACK,最终都会有tcp_ack()处理确认相关的内容,相关的代码如下:

    static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
    {
    ...
    	u32 prior_snd_una = tp->snd_una;
    	u32 ack = TCP_SKB_CB(skb)->ack_seq;
    ...
    	if (!(flag & FLAG_SLOWPATH) && after(ack, prior_snd_una)) {
    ...
    		//快速路径情况,用ack更新snd_una,由于快速路径,所以通告的窗口大小一定
    		//没有发生变化,所以不需要更新snd_wnd
    		tp->snd_una = ack;
    		flag |= FLAG_WIN_UPDATE;
    ...
    	} else {
    ...
    		//慢速路径下,调用函数更新窗口
    		flag |= tcp_ack_update_window(sk, skb, ack, ack_seq);
    ...
    	}
    ...
    }
    
    /* Update our send window.
     *
     * Window update algorithm, described in RFC793/RFC1122 (used in linux-2.2
     * and in FreeBSD. NetBSD's one is even worse.) is wrong.
     */
    static int tcp_ack_update_window(struct sock *sk, struct sk_buff *skb, u32 ack,
    				 u32 ack_seq)
    {
    	struct tcp_sock *tp = tcp_sk(sk);
    	int flag = 0;
    	u32 nwin = ntohs(tcp_hdr(skb)->window);
    
    	if (likely(!tcp_hdr(skb)->syn))
    		nwin <<= tp->rx_opt.snd_wscale;
    
    	if (tcp_may_update_window(tp, ack, ack_seq, nwin)) {
    		flag |= FLAG_WIN_UPDATE;
    		tcp_update_wl(tp, ack, ack_seq);
    
    		if (tp->snd_wnd != nwin) {
    			//更新发送窗口大小
    			tp->snd_wnd = nwin;
    
    			/* Note, it is the only place, where
    			 * fast path is recovered for sending TCP.
    			 */
    			tp->pred_flags = 0;
    			tcp_fast_path_check(sk);
    			//如果通告的最大接收窗口发生变化,更新max_window
    			if (nwin > tp->max_window) {
    				tp->max_window = nwin;
    				tcp_sync_mss(sk, inet_csk(sk)->icsk_pmtu_cookie);
    			}
    		}
    	}
    	//用ack更新snd_una
    	tp->snd_una = ack;
    
    	return flag;
    }
    

    3. 发送窗口对发送过程的影响

    这里要明白的是,发送窗口是实现流量控制的关键,它影响的只有新数据的发送过程,与重传无关,因为重传的数据一定是在对端接收能力之内。

    TCP之数据发送(二)中有看到新数据发送的两个关键函数tcp_write_xmit()和tcp_push_one(),而且二者非常相似,参考之前的笔记中分析的tcp_snd_wnd_test()和tcp_mss_split_point()就可以明白发送窗口是如何影响发送过程的。

    展开全文
  • 发送图文的话,要开启客服功能,坑的话就是在通过ticket 上传图片的时候回比较慢  加上划红线的这段代码就行了, 其他没什么了,比较繁琐吧,没有报错,要往文本里写才可以看到报错...
  • 引起原因 1,跨域; 2,请求头非默认情况。 默认请求头如下 Accept Accept-Language Content-Language Last-Event-ID Content-Type:只限于三个值application/x-...通常情况下,会将content-Type:applicati...
  • 今天抽空用jquery做了一下环信的...看下页面 Html 代码如下 <!DOCTYPE> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial...
  • RocketMQ消息发送常见错误与解决方案

    千次阅读 2020-09-30 20:42:07
    本文将结合自己使用RocketMQ的经验,对消息发送常见的问题进行分享,基本会遵循出现问题,分析问题、解决问题。 1、No route info of this topic 无法找到路由信息,其完整的错误堆栈信息如下: 而且很多读者朋友会...
  • UART

    千次阅读 多人点赞 2019-05-07 21:46:40
    UART基础知识 1、UART原理说明 发送数据时,CPU将并行数据写入UART,...UART之间以全双工方式传输数据,最精确的连线方法只有3根电线:TxD用于发送数据,RxD用于接收数据,Gnd用于给双发提供参考电平,连线如下...
  • SpringBoot整合RabbitMQ之发送接收消息实战

    万次阅读 热门讨论 2018-09-15 19:58:22
    3、当我们在上面创建好队列、交换机、路由及其绑定后,我们可以把整个项目跑起来,然后打开http://localhost:15672/ 访问RabbitMQ后端控制台,点击 Queues、Exchanges 栏目,即可看到我们创建好的队列、交换机。...
  • Dns解析出的ip不通导致无法发送邮件 问题:搬入公司新址,使用一运营商的专线网络后(原来使用电信宽带),经常有同事反馈有时无法发送邮件,有时能成功。今天有同事反馈无法发邮件,但他的账号在别人pc使用上是...
  • 基于JavaMail的Java邮件发送:简单邮件发送

    万次阅读 多人点赞 2016-06-14 21:56:35
    电子邮件的应用非常广泛,例如在某网站注册了一个...但这些应用不可能和我们自己平时发邮件一样,打开浏览器,登录邮箱,创建邮件再发送。本文将简单介绍如何通过 Java 代码来创建电子邮件,并连接邮件服务器发...
  • kafka实战篇(一):Producer消息发送实战

    千次阅读 多人点赞 2020-04-22 16:42:49
    本文对kafka生产者发送消息的流程进行了详细的解释和实战,其中包含了新版本的kafka对于同步发送消息和异步发送消息的api实现,以及kafka源码里的回调函数和架构内部的失败重试机制等都给出了底层的详细解释及实战...
  • SpringBoot发送Http请求-RestTemplate

    万次阅读 多人点赞 2020-05-14 12:05:41
    SpringBoot发送Http请求 [提前声明] 文章由作者:张耀峰 结合自己生产中的使用经验整理,最终形成简单易懂的文章 写作不易,转载请注明,谢谢! ... 前言 之前我写过一篇关于SpringBoot发送Http...但是使用这个工具发送请求很
  • 我们在用串口发送数据的时候首先将待发送的数据/符号转换为对应的ASCII码,然后将这些ASCII码按照二进制的方式一位一位地发送出去。 (注:以下图片来自https://blog.csdn.net/wityy/article/details/8234739) ...
  • 四、 后退 N 帧协议 发送方数据分类、 五、 后退 N 帧协议 发送方 需要 响应的事件、 六、 后退 N 帧协议 接收方 需要 响应的事件、 七、 后退 N 帧协议 运行细节、 八、 后退 N 帧协议 滑动窗口长度、 九、 ...
  • Java邮件发送详解

    万次阅读 多人点赞 2019-07-19 13:37:34
    我们可以尝试发送一封简单的邮件,首先请确保电脑可以连接网络。 创建包含邮件服务器的网络连接信息的Session对象。 创建代表邮件内容的Message对象 创建Transport对象,连接服务器,发送Message,关闭...
  • rabbitMQ消息发送失败处理策略

    千次阅读 2021-03-17 20:53:19
    一、发送失败的三种情况: (1)producter连接mq失败,消息没有发送到mq (2)producter连接mq...(2)发送失败处理:这种处理需要设置rabbitTemplate.setMandatory(true);然后分别对confirmCallback和returnCallback
  • 主要内容:TCP发送缓存的管理,包括发送缓存的初始化、sock发送缓存的动态调整、sock发送缓存的申请和释放。 内核版本:3.15.2。 TCP对发送缓存的管理是在两个层面上进行的,一个...来看下单个socket的发送缓存管理。
  • 最近写的一个通信框架中有两种最基本的消息发送方式:同步发送和异步发送。同步方式:消息的发送方发A送一条消息到接收端B,B收到消息之后需要对消息进行处理,然后发送ACK确认消息回A,A收到B的ACK之后就可以认为这...
  • 主要是看一下Springboot中发送邮件的方法,至于拦截Springboot全局异常之前的文章中有。一 发送邮件在Springboot中发送邮件非常简单。pom.xml引入maven依赖 org.springframework.boot spring-boot-starter-...
  • Java发送HTTPS请求

    万次阅读 多人点赞 2019-03-19 15:56:03
    前言 上篇文章介绍了 java 发送 http 请求,大家都知道发送http是不安全的。我也是由于对接了其他企业后总结了一套发送 https的工具。大家网上找方法很多的,但是可不是你粘过来就能用啊,...本文只介绍 发送 post...
  • 最近有个需求是将发送的邮件保存到已发送,一般来说最简单的做法是在服务器上配置,但是产品说,很多用户不知道这个选项,最好技术来实现,好吧,既然这样说了,干就完了! 查看JavaMail Api文档 邮件是在邮件...
  • httpclient发送webservice请求

    千次阅读 2018-01-30 09:28:49
    说下项目背景,公司项目需要通过webservice进行数据交互,拿到目标接口后,想研究下使用http请求发送webservice请求。 其中涉及到的技术点就是,http,xml解析。 下面就是代码部分了。 DefaultHttpClient ...
  • SpringBoot发送短信验证码实现

    千次阅读 热门讨论 2019-04-24 10:42:47
    短信验证码是通过发送验证码到手机的一种有效的验证码系统。主要用于验证用户手机的合法性及敏感操作的身份验证。常见的使用场景有:登录注册、信息修改、异常登录、找回密码等操作。 此篇文章记录后台框架...
  • Java实现定时发送邮件功能

    万次阅读 2018-08-30 22:49:25
    定时发送邮件 发送邮件在很多场景下都可以被使用到,例如:项目报错,将异常信息及时...在这里是结合线程发送邮件,首先创建发送邮件工具类: import java.util.ArrayList; import java.util.Iterator; import...
  • java创建kafka Producer 以便批量发送消息 /** * 创建Producer * @return */ @Override public Producer<String, String> createProducer() { //获取kafka配置信息,根据自己所需,也可写死 String ...
  • 以太坊上发送交易的九种办法

    万次阅读 2019-05-14 09:51:49
    本文的目的是为在以太坊生态中发送交易使用的各类技术,模式和机制提供一个指南。由于新技术层出不穷,本文也会随之更新,所以可以认为是未完待续的一个状态。 针对这个公认的大课题,本文将包含以下内容: Brief ...
  • 简单Rabbitmq 发送消息和接收消息

    千次阅读 2020-09-12 23:28:20
    1 在Rabbitmq配置文件中预先创建好交换器,队列,路由等信息。 2 创建生产者发送消息 @Autowired private RabbitTemplate rabbitTemplate; private void mqSendMessage(UserOperLog userOperLog) throws ...
  • STM32串口发送数据

    万次阅读 2019-05-15 15:35:53
    串口通信经常作为开发调试的工具,所以介绍下串口通信。 串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,大部分电子设备都支持该通讯方式,电子工程师在调试设备时也经常...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,263,977
精华内容 505,590
关键字:

发送先