【易语言拍照源码】【arm 源码剖析】【centos 源码lnmp】tcp socket源码

2024-12-26 04:05:57 来源:eschop源码 分类:探索

1.从 Linux源码 看 Socket(TCP)的accept
2.求一份unity中Socket-TCP从服务器接收数据方法的代码
3.一文从linux源码看socket的close基本概括
4.从Linux源码看Socket(TCP)的listen及连接队列
5.linux 网络编程Socket(TCP与UDP)
6.如何编写简单的socket网络程序 如何编写基于TCP协议的网络程序

tcp socket源码

从 Linux源码 看 Socket(TCP)的accept

       从 Linux 源码角度探究 Server 端 Socket 的 Accept 过程(基于 Linux 3. 内核),以下是一系列关键步骤的解析。

       创建 Server 端 Socket 需依次执行 socket、bind、listen 和 accept 四个步骤。其中,易语言拍照源码socket 系统调用创建了一个 SOCK_STREAM 类型的 TCP Socket,其操作函数为 TCP Socket 所对应的 ops。在进行 Accept 时,关键在于理解 Accept 的功能,即创建一个新的 Socket 与对端的 connect Socket 进行连接。

       在具体实现中,核心函数 sock->ops->accept 被调用。关注 TCP 实现即 inet_stream_ops->accept,其进一步调用 inet_accept。核心逻辑在于 inet_csk_wait_for_connect,用于管理 Accept 的超时逻辑,避免在超时时惊群现象的发生。

       EPOLL 的实现中,"惊群"现象是由水平触发模式下 epoll_wait 重新塞回 ready_list 并唤醒多个等待进程导致的。虽然 epoll_wait 自身在有中断事件触发时不惊群,但水平触发机制仍会造成类似惊群的arm 源码剖析效应。解决此问题,通常采用单线程专门处理 accept,如 Reactor 模式。

       针对"惊群"问题,Linux 提供了 so_reuseport 参数,允许多个 fd 监听同一端口号,内核中进行负载均衡(Sharding),将 accept 任务分散到不同 Socket 上。这样,可以有效利用多核能力,提升 Socket 分发能力,且线程模型可改为多线程 accept。

       在 accept 过程中,accept_queue 是关键成员,用于填充添加待处理的连接。用户线程通过 accept 系统调用从队列中获取对应的 fd。值得注意的是,当用户线程未能及时处理时,内核可能会丢弃三次握手成功的连接,导致某些意外现象。

       综上所述,centos 源码lnmp理解 Linux Socket 的 Accept 过程需要深入源码,关注核心函数与机制,以便优化 Server 端性能,并有效解决"惊群"等问题,提升系统处理能力。

求一份unity中Socket-TCP从服务器接收数据方法的代码

       接收的字节使用了protubuf反序列化,处理的时候要注意和服务器发送消息类型、大小定义一致。如果不需要可以直接删除,用服务器发送字符串也是一样

       using System.Collections;

       using System.Collections.Generic;

       using UnityEngine;

       using System.Net.Sockets;

       using System;

       using UnityEngine.Networking;

       using System.Text;

       using Google.Protobuf;

       using Pb;

       using System.Net;

       using System.IO;

       namespace Net

       {

       public class SocketClient

       {

       #region Public Variables

       public static SocketClient Instance { get; private set; }

       [Header("Network")]

       public string ipAdress = ".0.0.1";

       public int port = ;

       public float waitingMessagesFrequency = 1;

       public bool loggedIn { get; private set; }

       public bool FullLog = true;

       #endregion

       #region Private m_Variables

       private TcpClient m_Client;

       private NetworkStream m_NetStream = null;

       private byte[] m_Buffer = new byte[];

       private NetworkStream m_OutStream;

       [Tooltip("This value should be >= to Server waitingMessagesFrequency")]

       [Min(0)] private float m_DelayedCloseTime = 0.5f;

       #endregion

       #region Delegate Variables

       protected Action OnClientStarted = null; //Delegate triggered when client start

       protected Action OnClientClosed = null; //Delegate triggered when client close

       #endregion

       private void Awake()

       {

       if (Instance == null)

       Instance = this;

       }

       //Start client and stablish connection with server

       public void StartClient()

       {

       //Early out

       if (m_Client != null)

       {

       ClientLogError($"There is already a runing client on { ipAdress}::{ port}");

       return;

       }

       try

       {

       //Create new client

       m_Client = new TcpClient();

       //Set and enable client

       m_Client.BeginConnect(ipAdress, port, new AsyncCallback(OnConnect), null);

       ClientLogInfo($"Client Started on { ipAdress}::{ port}");

       OnClientStarted?.Invoke();

       }

       catch (SocketException)

       {

       ClientLogError("Socket Exception: Start Server first");

       OnClose();

       }

       }

       private void OnConnect(IAsyncResult asr)

       {

       ClientLogInfo("Connect Sucessful.");

       m_NetStream = m_Client.GetStream();

       m_Client.GetStream().BeginRead(m_Buffer, 0, m_Buffer.Length, new AsyncCallback(OnRead), m_Client);

       }

       #region Receive Message

       private void OnRead(IAsyncResult result)

       {

       OnReceivedMessage(m_Buffer);

       NetworkStream stream = m_Client.GetStream();

       lock (stream)

       {

       Array.Clear(m_Buffer, 0, m_Buffer.Length);

       m_Client.GetStream().BeginRead(m_Buffer, 0, m_Buffer.Length, new AsyncCallback(OnRead), m_Client);

       }

       }

       private void OnReceivedMessage(byte[] bytes)

       {

       ByteBuffer buffer = new ByteBuffer(bytes);

       OnRecieveMessageDeal(buffer, 0);

       }

       private void OnRecieveMessageDeal(ByteBuffer buffer, ushort length = 0)

       {

       // 判断传参length是否为0,如果不为0则代表非首次调用,不再取length值而使用传递的length

       ushort nextLength;

       if(length != 0)

       {

       nextLength = length;

       }

       else

       { // 判断传参length是否为0,如果为0则为首次调用,直接取出length后进行处理

       nextLength = buffer.ReadUInt();

       }

       uint pId = buffer.ReadUInt();

       ClientLogInfo("Length:" + nextLength + ".id:" + pId);

       byte[] bytes = buffer.ReadBytes(nextLength);

       NetLogic(pId, bytes);

       // 取出下一个length,如果为0则没有数据了,不为0则递归调用,并且传递已经取出的长度值

       nextLength = buffer.ReadUInt();

       if (nextLength != 0)

       {

       OnRecieveMessageDeal(buffer, nextLength);

       }

       }

       #endregion

       #region Process

       private void NetLogic(uint pid, byte[] bytes)

       {

       ClientLogInfo("Get Msg Id :" + pid);

       if (pid == 1)

       {

       SyncPid syncPid = SyncPid.Parser.ParseFrom(bytes);

       ClientLogInfo("sync pid:"+syncPid.Pid);

       }

       if (pid == )

       {

       BroadCast broadCast = BroadCast.Parser.ParseFrom(bytes);

       ClientLogInfo("broadCast-pid:" + broadCast.Pid);

       ClientLogInfo("broadCast-Tp:" + broadCast.Tp);

       ClientLogInfo("broadCast-Position-x:" + broadCast.P.X);

       ClientLogInfo("broadCast-Position-y:" + broadCast.P.Y);

       ClientLogInfo("broadCast-Position-z:" + broadCast.P.Z);

       ClientLogInfo("broadCast-Position-v:" + broadCast.P.V);

       }

       }

       #endregion

       #region Send Message

       private void WriteMessage(byte[] message)

       {

       MemoryStream memoryStream2;

       MemoryStream memoryStream = memoryStream2 = new MemoryStream();

       try

       {

       memoryStream.Position = 0L;

       BinaryWriter binaryWriter = new BinaryWriter(memoryStream);

       ushort num = (ushort)message.Length;

       binaryWriter.Write(message);

       binaryWriter.Flush();

       if (m_Client != null && this.m_Client.Connected)

       {

       byte[] array = memoryStream.ToArray();

       m_OutStream.BeginWrite(array, 0, array.Length, new AsyncCallback(OnWrite), null);

       }

       else

       {

       ClientLogError("client.connected----->>false");

       }

       }

       finally

       {

       if (memoryStream2 != null)

       {

       ((IDisposable)memoryStream2).Dispose();

       }

       }

       }

       private void OnWrite(IAsyncResult r)

       {

       try

       {

       m_OutStream.EndWrite(r);

       }

       catch (Exception ex)

       {

       ClientLogError("OnWrite--->>>" + ex.Message);

       }

       }

       public void SendMessage(ByteBuffer buffer)

       {

       this.SessionSend(buffer.ToBytes());

       buffer.Close();

       }

       private void SessionSend(byte[] bytes)

       {

       this.WriteMessage(bytes);

       }

       #endregion

       #region Close Client

       //Close client connection

       public void Close()

       {

       if (m_Client != null)

       {

       if (m_Client.Connected)

       {

       m_Client.Close();

       }

       m_Client = null;

       }

       loggedIn = false;

       }

       public void OnClose()

       {

       ClientLogError("Client Closed");

       //Reset everything to defaults

       if (m_Client.Connected)

       m_Client.Close();

       if (m_Client != null)

       m_Client = null;

       OnClientClosed?.Invoke();

       }

       #endregion

       #region ClientLog

       // Custom Client Log With Text Color

       public void ClientLogInfo(string msg)

       {

       if (FullLog)

       {

       Debug.Log($"<color=green>Client:</color>{ msg}");

       }

       }

       public void ClientLogWarning(string msg)

       {

       if (FullLog)

       {

       Debug.LogWarning($"<color=yellow>Client:</color>{ msg}");

       }

       }

       public void ClientLogError(string msg)

       {

       if (FullLog)

       {

       Debug.LogError($"<color=red>Client:</color>{ msg}");

       }

       }

       //Custom Client Log Without Text Color

       public void ClientLog(string msg)

       {

       if (FullLog)

       {

       Debug.Log($"Client:{ msg}");

       }

       }

       #endregion

       }

       }

一文从linux源码看socket的close基本概括

       理解TCP关闭过程的关键在于四次挥手,这个过程是主动关闭、被动关闭和同时关闭的统一体现。在主动关闭close(fd)的过程中,通过C语言中的mvc源码分析close(int fd)函数调用系统调用sys_close,进而执行filp_close方法。随后,fput函数处理多进程中的socket引用问题,确保父进程也正确关闭socket。在f_op->release的实现中,我们关注socket与file的关系以及close(fd)调用链。随着状态机的变迁,TCP从FIN_WAIT1变迁至FIN_WAIT2,设置一个TCP_FIN_WAIT2定时器,防止由于对端未回应导致的长时间等待。FIN_WAIT2状态等待对端的FIN,完成最后两次挥手。接收对端FIN后,状态变化至time_wait,原socket资源被回收,并在时间等待超时后从系统中清除。在被动关闭中,接收FIN进入close_wait状态,应用关闭连接时改变状态为last_ack,并发送本端的FIN。被动关闭的idea下载源码后两次挥手后,连接关闭。出现大量close_wait通常与应用检测到对端FIN时未及时关闭有关,解决方法包括调整连接池的参数或加入心跳检测。操作系统通过包活定时器在超时后强制关闭连接。进程退出时会关闭所有文件描述符,再次触发filp_close函数。在Java中,通过重写finalize方法,GC会在释放内存时关闭未被引用的socket,但不可完全依赖GC来管理socket资源,以避免潜在的内存泄露问题。总结,深入理解TCP关闭过程有助于优化网络应用程序的性能和稳定性,同时阅读Linux内核源代码需要耐心和系统性的方法。

从Linux源码看Socket(TCP)的listen及连接队列

       了解Linux内核中Socket (TCP)的"listen"及连接队列机制是深入理解网络编程的关键。本文将基于Linux 3.内核版本,从源码角度解析Server端Socket在进行"listen"时的具体实现。

       建立Server端Socket需要经历socket、bind、listen、accept四个步骤。本文聚焦于"listen"步骤,深入探讨其内部机理。

       通过socket系统调用,我们可以创建一个基于TCP的Socket。这里直接展示了与TCP Socket相关联的操作函数。

       接着,我们深入到"listen"系统调用。注意,glibc的INLINE_SYSCALL对返回值进行了封装,仅保留0和-1两种结果,并将错误码的绝对值记录在errno中。其中,backlog参数至关重要,设置不当会引入隐蔽的陷阱。对于Java开发者而言,框架默认backlog值较小(默认),这可能导致微妙的行为差异。

       进入内核源码栈,我们发现内核对backlog值进行了调整,限制其不超过内核参数设置的somaxconn值。

       核心调用程序为inet_listen。其中,除了fastopen外的逻辑(fastopen将在单独章节深入讨论)最终调用inet_csk_listen_start,将sock链入全局的listen hash表,实现对SYN包的高效处理。

       值得注意的是,SO_REUSEPORT特性允许不同Socket监听同一端口,实现内核级的负载均衡。Nginx 1.9.1版本启用此功能后,性能提升3倍。

       半连接队列与全连接队列是连接处理中的关键组件。通常提及的sync_queue与accept_queue并非全貌,sync_queue实际上是syn_table,而全连接队列为icsk_accept_queue。在三次握手过程中,这两个队列分别承担着不同角色。

       在连接处理中,除了qlen与sk_ack_backlog计数器外,qlen_young计数器用于特定场景下的统计。SYN_ACK的重传定时器在内核中以ms为间隔运行,确保连接建立过程的稳定。

       半连接队列的存在是为抵御半连接攻击,避免消耗大量内存资源。通过syn_cookie机制,内核能有效防御此类攻击。

       全连接队列的最大长度受到限制,超过somaxconn值的连接会被内核丢弃。若未启用tcp_abort_on_overflow特性,客户端可能在调用时才会察觉到连接被丢弃。启用此特性或增大backlog值是应对这一问题的策略。

       backlog参数对半连接队列容量产生影响,导致内核发送cookie校验时出现常见的内存溢出警告。

       总结而言,TCP协议在数十年的演进中变得复杂,深入阅读源码成为分析问题的重要途径。本文深入解析了Linux内核中Socket (TCP)的"listen"及连接队列机制,旨在帮助开发者更深入地理解网络编程。

linux 网络编程Socket(TCP与UDP)

       TCP/IP协议族主要分为网络层、传输层与应用层。网络层包括IP协议、ICMP协议、ARP协议、RARP协议与BOOTP协议;传输层则有TCP协议与UDP协议;而应用层则有FTP、HTTP、TELNET、SMTP、DNS等协议。

       HTTP协议基于请求/响应模型,其底层仍依赖TCP协议。不过,当前有研究探讨基于TCP+UDP混合的HTTP协议。

       Socket编程中,基本操作包括:socket()函数用于创建套接字,bind()函数用于绑定套接字与特定地址,listen()和connect()函数分别用于服务器监听连接与客户端建立连接,accept()函数用于接受连接请求,read()与write()等函数用于读取与写入数据。推荐使用recvmsg()/sendmsg()函数,它们是通用的I/O函数,能替代其他函数。

       TCP与UDP协议的主要区别在于UDP处理的细节比TCP少。UDP不保证消息被传送到目的地,也不保证数据包的顺序。UDP数据发出去后只能寄希望于抵达。

       TCP示例代码中,服务器端使用SOCK_STREAM参数打开TCP连接,客户端示例需要与服务器端交互。

       UDP示例代码包含服务器端与客户端,通过UDP套接字进行数据交换。

       Linux服务器开发/架构师面试题、学习资料、教学视频与学习路线图,免费分享,有兴趣者可加入学习交流群。

如何编写简单的socket网络程序 如何编写基于TCP协议的网络程序

       ã€€ã€€ä¸‹é¢æ˜¯ä¸ªäººç”¨äº†ä¸€ä¸ªåˆ†é’Ÿå·¦å³çš„时间编写的程序,在这编写过程中,非常重要的一点就是: 要理解 tcp协议编写程序的原理,即编写服务器端的过程,以及编写客户端的过程。 只要把握这两点就可以很容易编写出来了,但是要快速编写出这个程序,那么VC6.0开发工具里,最好要安装一个番茄插件,这个插件可以快速提高你的编写程序的效率,还有也要安装msdn 文档,这样在编写过程中,遇到对某个函数的参数想不全的时候,使用msdn就能快速帮你回忆了。 呵呵,如果你那一天去面试一家牛逼的公司的哇,很有可能就是 在笔试完成之后,就要进行机试了,这就完全考查出你的真正编程水平了。 能在极短时间里完成一个socket网络程序,那么就可以令面试官感到非常满意了。 不过,这个程序,还没有连接数据库,以后再继续搞了。

       ã€€ã€€å¦‚果你去面试 深圳科技园 那家 伟易达 集团公司的软件工程师的哇,那么机试题目就是这个。 当时我去面试,首先进行笔试,面试官对我笔试成绩比较满意,所以就叫我留下来吃顿饭,下午进行机试。 当时我应聘岗位是Linux系统工程师C语言, 可是笔试题目,不但考核C,还考核C++,JavaScript,html。 我感觉好奇怪,心里想,好像我是应聘VC++开发那个岗位了。 于是我等到下午,他拿来机试题目之时,才真正明白,果然是他要安排我从事VC++开发了,题目就是:编写基于TCP/IP协议网络程序,并实现简单的聊天程序,而且要连接数据库。 当时我又失望了。 于是我就提出,我不想做这个题目,因为我是想应聘Linux系统C语言开发的。 就这样失望的走了。

       ã€€ã€€ä¸‹é¢æ˜¯ä¸ªäººå®Œå…¨èƒ½è¿è¡Œçš„代码:

       ã€€ã€€æœåŠ¡å™¨ç«¯æºç ï¼š

       ã€€ã€€#include<stdio.h>

       #include <Winsock2.h>

       #pragma comment (lib,"ws2_.lib")

       ã€€ã€€int main()

       {

        WORD wVersionRequested;

        WSADATA wsaData;

        int err;

        wVersionRequested = MAKEWORD( 2, 2 );

        err = WSAStartup( wVersionRequested, &wsaData );

        if ( err != 0 ) {

        return 0;

        }

       if ( LOBYTE( wsaData.wVersion ) != 2 ||

        HIBYTE( wsaData.wVersion ) != 2 ) {

        WSACleanup( );

        return 0;

        }

       ã€€ã€€SOCKET socketServer=socket(AF_INET,SOCK_STREAM,0);

       ã€€ã€€SOCKADDR_IN addrServer;

       ã€€ã€€addrServer.sin_family=AF_INET;

       ã€€ã€€addrServer.sin_addr.S_un.S_addr=htonl(INADDR_ANY);

       ã€€ã€€addrServer.sin_port=htons();

       ã€€ã€€bind(socketServer, (struct sockaddr *)&addrServer, sizeof(struct sockaddr));

       ã€€ã€€listen(socketServer, 5);

       ã€€ã€€SOCKADDR_IN addrClient;

       ã€€ã€€int addrLen=sizeof(SOCKADDR_IN);

       ã€€ã€€char sendBuf[];

       ã€€ã€€char recvBuf[];

       ã€€ã€€int i=1;

        while(1)

        {

        printf("服务器端等待第%d个客户端连接请求...\n", i++);

       ã€€ã€€SOCKET newsocketServer=accept(socketServer,(struct sockaddr *)&addrClient, &addrLen);

       ã€€ã€€if(newsocketServer!=INVALID_SOCKET)

        {

        printf("服务器端与客户端连接成功...\n");

        }

       ã€€ã€€memset(sendBuf,0,);

       ã€€ã€€sprintf(sendBuf,"Welcome you to come here");

       ã€€ã€€send(newsocketServer, sendBuf, strlen(sendBuf)+1,0);

       ã€€ã€€memset(recvBuf,0,);

       ã€€ã€€recv(newsocketServer,recvBuf,,0);

       ã€€ã€€printf("服务器端收到信息:%s\n",recvBuf);

       ã€€ã€€closesocket(newsocketServer);

        }

       ã€€ã€€WSACleanup();

       ã€€ã€€return 0;

       }

       ã€€ã€€æ­¤æ–‡ç« æ¥è‡ªäºŽä¸ªäººåšå®¢ï¼š 阿浪博客 /wenxianliang@/

       ã€€ã€€å®¢æˆ·ç«¯æºç ï¼š

       ã€€ã€€#include<stdio.h>

       #include <Winsock2.h>

       #pragma comment (lib,"ws2_.lib")

       ã€€ã€€int main()

       {

        WORD wVersionRequested;

        WSADATA wsaData;

        int err;

        wVersionRequested = MAKEWORD( 2, 2 );

        err = WSAStartup( wVersionRequested, &wsaData );

        if ( err != 0 ) {

        return 0;

        }

       if ( LOBYTE( wsaData.wVersion ) != 2 ||

        HIBYTE( wsaData.wVersion ) != 2 ) {

        WSACleanup( );

        return 0;

        }

        SOCKET socketClient=socket(AF_INET,SOCK_STREAM,0);

        SOCKADDR_IN addrServer;

        addrServer.sin_family=AF_INET;

        addrServer.sin_addr.S_un.S_addr=inet_addr(".0.0.1");

        addrServer.sin_port=htons();

        char sendBuf[];

        char recvBuf[];

       ã€€ã€€printf("客户端向服务器端连接请求...\n");

       ã€€ã€€int Isconnect=connect(socketClient, (struct sockaddr *)&addrServer, sizeof(struct sockaddr));

       ã€€ã€€if(Isconnect!=0)

        {

        printf("客户端无法连接服务器端...\n");

       ã€€ã€€return 0;

        }

       ã€€ã€€printf("客户端已成功连接服务器端...\n");

       ã€€ã€€memset(recvBuf,0,);

        recv(socketClient,recvBuf,,0);

       ã€€ã€€printf("客户端收到信息:%s\n",recvBuf);

       ã€€ã€€memset(sendBuf,0,);

        sprintf(sendBuf,"Hello , I am Mr Wen !");

        send(socketClient, sendBuf, strlen(sendBuf)+1,0);

        closesocket(socketClient);

        WSACleanup();

        return 0;

       }

本文地址:http://581.net.cn/news/83b271097206.html 欢迎转发