1.tcp ������Դ��
2.Nginx源码分析 - HTTP模块篇 - TCP连接建立过程
3.TCP长连接服务优雅重启背后的服p服秘密
4.TCP之深入浅出send&recv
5.Netty源码-一分钟掌握4种tcp粘包解决方案
tcp ������Դ��
源代码奉上,流程图。器务器。源码源码。服p服这个太简单了,器务器你自己看看。源码源码影视源码卡。服p服。器务器。源码源码。服p服。器务器。源码源码教育社区源码
//TCP
//服务器端程序
#include< stdio.h >
#include< stdlib.h >
#include< windows.h >
#include< winsock.h >
#include< string.h >
#pragma comment( lib,服p服 "ws2_.lib" )
#define PORT
#define BACKLOG
#define TRUE 1
void main( void )
{
int iServerSock;
int iClientSock;
char *buf = "hello, world!\n";
struct sockaddr_in ServerAddr;
struct sockaddr_in ClientAddr;
int sin_size;
WSADATA WSAData;
if( WSAStartup( MAKEWORD( 1, 1 ), &WSAData ) )//初始化
{
printf( "initializationing error!\n" );
WSACleanup( );
exit( 0 );
}
if( ( iServerSock = socket( AF_INET, SOCK_STREAM, 0 ) ) == INVALID_SOCKET )
{
printf( "创建套接字失败!\n" );
WSACleanup( );
exit( 0 );
}
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons( PORT );//监视的端口号
ServerAddr.sin_addr.s_addr = INADDR_ANY;//本地IP
memset( & ( ServerAddr.sin_zero ), 0, sizeof( ServerAddr.sin_zero ) );
if( bind( iServerSock, ( struct sockaddr * )&ServerAddr, sizeof( struct sockaddr ) ) == -1 )
{
printf( "bind调用失败!\n" );
WSACleanup( );
exit( 0 );
}
if( listen( iServerSock, BACKLOG ) == -1 )
{
printf( "listen调用失败!\n" );
WSACleanup( );
exit( 0 );
}
while( TRUE )
{
sin_size = sizeof( struct sockaddr_in );
iClientSock = accept( iServerSock, ( struct sockaddr * )&ClientAddr, &sin_size );
if( iClientSock == -1 )
{
printf( "accept调用失败!\n" );
WSACleanup( );
exit( 0 );
}
printf( "服务器连接到%s\n", inet_ntoa( ClientAddr.sin_addr ) );
if( send( iClientSock, buf, strlen( buf ), 0 ) == -1 )
{
printf( "send调用失败!" );
closesocket( iClientSock );
WSACleanup( );
exit( 0 );
}
}
}
/////客户端程序
#include< stdio.h >
#include< stdlib.h >
#include< windows.h >
#include< winsock.h >
#include< string.h >
#pragma comment( lib, "ws2_.lib" )
#define PORT
#define BACKLOG
#define TRUE 1
#define MAXDATASIZE
void main( void )
{
int iClientSock;
char buf[ MAXDATASIZE ];
struct sockaddr_in ServerAddr;
int numbytes;
// struct hostent *he;
WSADATA WSAData;
// int sin_size;
/* if( ( he = gethostbyname( "liuys" ) ) == NULL )
{
printf( "gethostbyname调用失败!" );
WSACleanup( );
exit( 0 );
}
*/
if( WSAStartup( MAKEWORD( 1, 1 ), &WSAData ) )//初始化
{
printf( "initializationing error!\n" );
WSACleanup( );
exit( 0 );
}
if( ( iClientSock = socket( AF_INET, SOCK_STREAM, 0 ) ) == INVALID_SOCKET )
{
printf( "创建套接字失败!\n" );
WSACleanup( );
exit( 0 );
}
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons( PORT );
// ServerAddr.sin_addr = *( ( struct in_addr * )he->h_addr );
ServerAddr.sin_addr.s_addr = inet_addr( "..2." );//记得换IP
memset( &( ServerAddr.sin_zero ), 0, sizeof( ServerAddr.sin_zero ) );
if( connect( iClientSock, ( struct sockaddr * ) & ServerAddr, sizeof( struct sockaddr ) ) == -1 )
{
printf( "connect失败!" );
WSACleanup( );
exit( 0 );
}
numbytes = recv( iClientSock, buf, MAXDATASIZE, 0 );
if( numbytes == -1 )
{
printf( "recv失败!" );
WSACleanup( );
exit( 0 );
}
buf[ numbytes ] = '\0';
printf( "Received: %s", buf );
closesocket( iClientSock );
WSACleanup( );
}
/////UDP
//服务器
#include< stdio.h >
#include< string.h >
#include< winsock.h >
#include< windows.h >
#pragma comment( lib, "ws2_.lib" )
#define PORT
#define BACKLOG
#define TRUE 1
#define MAXDATASIZE
void main( void )
{
int iServerSock;
// int iClientSock;
int addr_len;
int numbytes;
char buf[ MAXDATASIZE ];
struct sockaddr_in ServerAddr;
struct sockaddr_in ClientAddr;
WSADATA WSAData;
if( WSAStartup( MAKEWORD( 1, 1 ), &WSAData ) )
{
printf( "initializationing error!\n" );
WSACleanup( );
exit( 0 );
}
iServerSock = socket( AF_INET, SOCK_DGRAM, 0 );
if( iServerSock == INVALID_SOCKET )
{
printf( "创建套接字失败!\n" );
WSACleanup( );
exit( 0 );
}
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons( PORT );//监视的端口号
ServerAddr.sin_addr.s_addr = INADDR_ANY;//本地IP
memset( & ( ServerAddr.sin_zero ), 0, sizeof( ServerAddr.sin_zero ) );
if( bind( iServerSock, ( struct sockaddr * )&ServerAddr, sizeof( struct sockaddr ) ) == -1 )
{
printf( "bind调用失败!\n" );
WSACleanup( );
exit( 0 );
}
addr_len = sizeof( struct sockaddr );
numbytes = recvfrom( iServerSock, buf, MAXDATASIZE, 0, ( struct sockaddr * ) & ClientAddr, &addr_len );
if( numbytes == -1 )
{
printf( "recvfrom调用失败!\n" );
WSACleanup( );
exit( 0 );
}
printf( "got packet from %s\n", inet_ntoa( ClientAddr.sin_addr ) );
printf( "packet is %d bytes long\n", numbytes );
buf[ numbytes ] = '\0';
printf( "packet contains \"%s\"\n", buf );
closesocket( iServerSock );
WSACleanup( );
}
//客户端
#include< stdio.h >
#include< stdlib.h >
#include< windows.h >
#include< winsock.h >
#include< string.h >
#pragma comment( lib, "ws2_.lib" )
#define PORT
#define MAXDATASIZE
void main( void )
{
int iClientSock;
struct sockaddr_in ServerAddr;
int numbytes;
char buf[ MAXDATASIZE ] = { 0 };
WSADATA WSAData;
if( WSAStartup( MAKEWORD( 1, 1 ), &WSAData ) )
{
printf( "initializationing error!\n" );
WSACleanup( );
exit( 0 );
}
if( ( iClientSock = socket( AF_INET, SOCK_DGRAM, 0 ) ) == -1 )
{
printf( "创建套接字失败!\n" );
WSACleanup( );
exit( 0 );
}
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons( PORT );
ServerAddr.sin_addr.s_addr = inet_addr( "..2." );//记得换IP
memset( &( ServerAddr.sin_zero ), 0, sizeof( ServerAddr.sin_zero ) );
numbytes = sendto( iClientSock, buf, strlen( buf ), 0, ( struct sockaddr * ) & ServerAddr, sizeof( struct sockaddr ) );
if( numbytes == -1 )
{
printf( "sendto调用失败!\n" );
WSACleanup( );
exit( 0 );
}
printf( "sent %d bytes to %s\n", numbytes, inet_ntoa( ServerAddr.sin_addr ) );
closesocket( iClientSock );
WSACleanup( );
}
Nginx源码分析 - HTTP模块篇 - TCP连接建立过程
Nginx源码分析 - HTTP模块篇 - TCP连接建立过程
在上一章节中,我们已经了解了HTTP模块的器务器初始化过程。本章节将深入剖析监听套接字的源码源码初始化函数以及Nginx连接的全程流程。 首先, ngx_.ipv4.tcp_wmem值或命令'cat /proc/sys/net/ipv4/tcp_wmem'。以笔者服务器为例,发送缓冲区大小为、、。通过程序可以修改当前tcp socket的发送缓冲区大小,只影响特定的rsi源码免费指标socket。
接收缓冲区用于缓存网络上来的数据,直至应用进程读取为止。当应用进程未读取数据且接收缓冲区已满时,收端会通知发端接收窗口关闭(win=0),实现TCP的流量控制。
接收缓冲区大小可以通过查看/etc/sysctl.ronf下的net.ipv4.tcp_rmem值或命令'cat /proc/sys/net/ipv4/tcp_rmem'获取。同样,可以通过修改程序大小修改接收缓冲区,仅影响当前特定socket。
TCP的四层模型包括应用层、传输层、微服务pdf源码网络层和数据链路层。应用层创建socket并建立连接后,可以调用send函数发送数据。传输层处理数据,以TCP为例,其主要功能包括流量控制、拥塞控制等。
当发送数据时,数据会从应用层、传输层、网络层、脱盐水指标源码数据链路层依次传递。上图为send函数源码调用逻辑图,若对源码感兴趣,可查阅net/tcp.c获取详细实现。
recv函数实现类似,从数据链路层接收数据帧,通过网卡驱动处理后,进入内核进行协议层处理,最终将数据放入socket的接收缓冲区。
在实际应用中,非阻塞send时,发送端可能发送了大量数据,但实际只发送了部分,缓冲区中仍有大量数据未发送。接收端recv获取数据时,可能只收到部分数据。这种情况下,应用层需要正确处理超时、断开连接等情况。
总结来说,TCP的send和recv函数分别在应用层和传输层实现数据的发送和接收,通过内核的缓冲区控制数据的流动。正确理解这些原理对于网络编程至关重要。
Netty源码-一分钟掌握4种tcp粘包解决方案
TCP报文的传输过程涉及内核中recv缓冲区和send缓冲区。发送端,数据先至send缓冲区,经Nagle算法判断是否立即发送。接收端,数据先入recv缓冲区,再由内核拷贝至用户空间。
粘包现象源于无明确边界。解决此问题的关键在于界定报文的分界。Netty提供了四种方案来应对TCP粘包问题。
Netty粘包解决方案基于容器存储报文,待所有报文收集后进行拆包处理。容器与拆包处理分别在ByteToMessageDecoder类的cumulation与decode抽象方法中实现。
FixedLengthFrameDecoder是通过设置固定长度参数来识别报文,非报文长度,避免误判。
LineBasedFrameDecoder以换行符作为分界符,确保准确分割报文,避免将多个报文合并。
LengthFieldPrepender通过设置长度字段长度,实现简单编码,为后续解码提供依据。
LengthFieldBasedFrameDecoder则是一种万能解码器,能够解密任意格式的编码,灵活性高。
实现过程中涉及的参数包括:长度字段的起始位置offset、长度字段占的字节数lengthFieldLength、长度的调整lengthAdjustment以及解码后需跳过的字节数initialBytesToStrip。
在实际应用中,为自定义协议,需在服务器与客户端分别实现编码与解码逻辑。服务器端负责发送经过编码的协议数据,客户端则接收并解码,以还原协议信息。