1、创建udp的socket句柄

// 当host_port为0时,则表示让操作系统自动分配
bool createUdpSocket(string host_ip,unsigned short host_port, int& sock_fd)
{
    sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    )
    {
        return false;
    }

    };
    inet_pton(AF_INET,host_ip.c_str(), &(client_addr.sin_addr));
    client_addr.sin_port =htons(host_port);
    client_addr.sin_family = AF_INET;

    )
    {
        close(sock_fd);
        sock_fd = -;
        return false;
    }

    //获取操作系统分配的端口
    struct sockaddr_storage sock_addr;
    socklen_t addr_size = sizeof(struct sockaddr_storage);

    getsockname(sock_fd, (struct sockaddr*)&sock_addr, &addr_size);

    sockaddr_in sin ;
    memcpy(&sin,&sock_addr,addr_size);

    host_ip = inet_ntoa(sin.sin_addr);
    host_port = ntohs(sin.sin_port);

    // 设置socket为非阻塞
#ifdef WIN32
    unsigned ;
    ioctlsocket(sock_fd, FIONBIO, &arg) ;
    ioctlsocket(sock_fd, FIONBIO, &arg) ;
#endif
#ifdef LINUX
    );
    fcntl(sock_fd, F_SETFL, arg | O_NONBLOCK);
#endif

    return true;

}

2、发送udp数据包

int sendUdpData(int socket_fd,char* buff,int buff_len,struct sockaddr* dest_addr)
{
     ;
    ssize_t send_len = ;

    do
    {
        )
        {
            sleep_ms(*count);
        }

        //考虑网络不好时,需要尝试发送多次
        send_len = sendto(socket_fd, buff, ssize_t(buff_len), , dest_addr, sizeof(struct sockaddr));
        count++;
    } && errno == EAGAIN && count<=);
    return int(send_len);
}

3、发送udp广播包

int sendBroadUdpData(int sock_fd,char* buff,int buff_len)
{
    // 将端口设置为允许广播包
    ;
#ifdef WIN32
    setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, (const char *)&broadcast, sizeof(broadcast));
#else
    setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast));
#endif

    struct sockaddr_in svr_addr;
    memset(&svr_addr, , sizeof(svr_addr));
    svr_addr.sin_family = AF_INET;
    svr_addr.sin_port = htons(BROAD_CAST_PORT);

    int server_ip;
    inet_pton(AF_INET, "255.255.255.255", (void *)&server_ip);
    svr_addr.sin_addr.s_addr = server_ip;

    sendUdpData(sock_fd, buff, buff_len, (struct sockaddr*)&svr_addr);

}

4、接收udp的数据包

利用poll或epoll模型,当某个socket_fd有数据可读时,即可返回进行相应的处理

{
    struct sockaddr_in client_addr;
    int len = sizeof(struct sockaddr);
    ];
    ;

    recv_len = recvfrom(socket_fd, recv_buff, , (struct sockaddr *)&client_addr, (socklen_t *)&len)
    )
    {
        processMsg(recv_buff, recv_len, client_addr);
    }
}

5、poll模型的构建,同时监控多个fd

{
    ;
#ifdef LINUX
    struct pollfd wait_fd[maxCount];
#endif

#ifdef WIN32
    WSAPOLLFD wait_fd[maxCount];
#endif

    ;

    listen_fds.clear();
    GetListenFd(listen_fds);
    ; index < (int)listen_fds.size(); index++)
    {
        wait_fd[real_count].fd = listen_fds[index];
        wait_fd[real_count].events = POLLIN | POLLOUT;
        real_count++;
    }

#ifdef LINUX
    ); //100毫秒超时
#endif

#ifdef WIN32
    );
#endif

    )
    {
        usleep();
    }
    else if (res)
    {
        int current_fd;
        ; index < real_count; index++)
        {
            current_fd = wait_fd[index].fd;
            )
            {
                recvfrom(current_fd, recv_buff, , (struct sockaddr *)&client_addr, (socklen_t *)&alen);

                bool is_listen_fd = false; //是否是监听句柄
                ; pos < (int)listen_fds.size(); pos++)
                {
                    if (current_fd == listen_fds[pos])
                    {
                        is_listen_fd = true;
                        break;
                    }
                }
            }

            )

                usleep();
            }
        }
    }
    else
    {
        printf("time out.\n");
    }

}
struct sockaddr_in addr;
socklen_t addr_len = sizeof (struct sockaddr_in);
, ()
{
    if (errno == EAGAIN || errno == EINTR)
    {
        len = ;
    }
}
addr_ip = addr.sin_addr.s_addr;
addr_port = ntohs(addr.sin_port);

6、创建tcp句柄并监听客户端的连接请求

bool createTcpSocket(string host_ip,unsigned short host_port, int& sock_fd)
{
    ;
    };
    new_sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //建立TCP套接字
    )
    {
        return false;
    }

    struct in_addr ip_addr;
    inet_aton(host_ip, &ip_addr)
    svr_addr.sin_addr.s_addr = ip_addr.s_addr;
    svr_addr.sin_port = htons(host_port);
    svr_addr.sin_family = AF_INET;

    )
    {
        close(new_sockfd);
        return false;
    }

     * ;
    )
    {
        printf("setsockopt SO_RCVBUF error.\n ");
    }
     * ;
    )
    {
        printf("setsockopt SO_SNDBUF error.\n ");
    }

    // 设置非阻塞
    );
    )
    {
        return false;
    }

    // 设置句柄重用
    ;
    )
    {
        return false;
    }

    )
    {
        sock_fd = new_sockfd;
        ) < )
        {
            close(sock_fd);
            sock_fd = -;
            return false;
        }
        return true;
    }
    else
    {
        return false;
    }
}

7、接受客户端的tcp连接请求

int OnRecv()
{
    int length = sizeof(struct sockaddr_in);
    int clientfd = accept(sock_fd,(struct sockaddr *)&client_addr,(socklen_t*)&length);
     )
    {
        ;
    }

    unsigned int clientip = client_addr.sin_addr.s_addr;

    // 设置非阻塞
    );
    )
    {
        return false;
    }

    //设置客户端发送和接收缓冲区大小
     * ;
    setsockopt(clientfd, SOL_SOCKET, SO_RCVBUF, (char*)&buff_size, sizeof(buff_size));
    setsockopt(clientfd, SOL_SOCKET, SO_SNDBUF, (char*)&buff_size, sizeof(buff_size));

    MsgHandler* msg_handler = new MsgHandler(clientfd); // 在msg_handler对象中接收该句柄发送的具体数据

}

8、接收客户端的具体数据

int MsgHandler::OnRecv()
{
    *];
    memset(recv_buff, 0x00, sizeof(recv_buff));
    ;
    do
    {
        recv_len = recv(clientfd, recv_buff, , );
    } && errno == EINTR);

    )
    {
        )
        {
            printf("socket closed by client.\n");
            delete this;
            ;
        }
    }
    else if (errno == EAGAIN)
    {
        ; //暂时阻塞
    }
    else
    {
        delete this;
        ;
    }
    ;
}

//本地维护一个接收缓冲区
    #define MAX_BUFF_LEN (10 * 1024 * 1024)
    recv_buff = new char[MAX_BUFF_LEN];
    start_buff = recv_buff;

    memmove(recv_buff,start_buff,data_len); //移动数据位置到缓冲区的头部
    start_buff = recv_buff ;

9、利用tcp来发送消息

struct SendMsg
{
    unsigned int send; //消息已经发送的长度
    string data;
    SendMsg()
    {
        send = ;
        data.clear();
    }
    SemdMsg()
    {
    }
    ;}
}
queue<SendMsg> msg_queue;
while (!msg_queue.empty())
{
    SendMsg& msg = msg_queue.front();
    int msg_len = msg.data.size() - send;
    // 发送数据,保证需要发送的数据全部发送完
    int send_len = SendTCPMsg((char*)msg.data.c_str()+msg.send, msg_len);
    if (send_len != msg_len)
    {
        msg_queue.front().send += send_len;
        break;
    }
    msg_queue.pop();
}
int SendTcpMsg(char* buff, int len)
{
    int ret;
    ;
    int _len = len;
    errno = ;
    )
    {
        ret = send(_sock_fd,();
         )
        {
            if ( errno == EINTR || errno == EAGAIN )
            {
                usleep();
                continue;
            }
            break;
        }
        _len -= ret;
        _snd += ret;
    }

    return _snd;
}

10、客户端创建socket并发起连接请求

int ClientSocketConnect()
{
    sock_status = SOCK_CLOSED;
    sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    //地址复用
    ;
    setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse));

    // 非阻塞
    );
    fcntl(sock_fd, F_SETFL, val | O_NONBLOCK) ;

    //建立连接
    struct sockaddr_in recvAddr;
    memset(&recvAddr, , sizeof(recvAddr));
    recvAddr.sin_family = AF_INET;
    recvAddr.sin_addr.s_addr = inet_addr(server_ip.c_str());
    recvAddr.sin_port = htons(server_port);

    struct timeval tv;
    tv.tv_sec =  ;
    tv.tv_usec =   ;

    fd_set fd_write ;
     ;
    int len = sizeof(int);

    // 连接服务器
    int ret_code = connect(sock_fd, (sockaddr *)&recvAddr, sizeof(sockaddr));
    )
    {
        FD_ZERO(&fd_write);
        FD_SET(sock_fd, &fd_write );

        , NULL , &fd_write, NULL, &tv) > )
        {
            if( FD_ISSET(sock_fd,&fd_write) )
            {
                getsockopt(_sock_fd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len);
                )
                {
                    sock_status = SOCK_CONNECTED;
                }
                else
                {
                    sock_status = SOCK_CLOSED;
                }
            }
        }
    }
    else
    {
        sock_status = SOCK_CONNECTED;
    }

    if(sock_status == SOCK_CLOSED)
    {
        close(_sock_fd);
        sock_fd = - ;
        ;
    }
    else
    {
        *;
        setsockopt(sock_fd, SOL_SOCKET, SO_RCVBUF, (char*)&buff_size, sizeof(buff_size));
        setsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF, (char*)&buff_size, sizeof(buff_size));
    }

    //开始发送和接收数据

}

socket网络编程实践要点的更多相关文章

  1. Java之Socket网络编程实践

    转自:http://my.oschina.net/leejun2005/blog/104955#comments 一.TCP/IP协议 既然是网络编程,涉及几个系统之间的交互,那么首先要考虑的是如何准 ...

  2. Socket 网络编程实践经验

    目录 目录 相关文章 Socket 与 HTTP 的区别 生产实践考虑 网络断开重连问题 Heartbeat 心跳机制 使用非阻塞模式下的 select 函数进行 Socket 连接检查 会话过期问题 ...

  3. windows socket 网络编程

    样例代码就在我的博客中,包含六个UDP和TCP发送接受的cpp文件,一个基于MFC的局域网聊天小工具project,和此小工具的全部执行时库.资源和执行程序.代码的压缩包位置是http://www.b ...

  4. Socket网络编程(案例)

    Socket:套接字 java.net包 1.流式套接字:基于TCP协议的Socket网络编程 工作方式: 1.客户端A连接到服务器: 2.服务器建立连接并把客户端A添加到列表: 3.客户端B.C.. ...

  5. Linux Socket 网络编程

    Linux下的网络编程指的是socket套接字编程,入门比较简单.在学校里学过一些皮毛,平时就是自学玩,没有见识过真正的socket编程大程序,比较遗憾.总感觉每次看的时候都有收获,但是每次看完了之后 ...

  6. Python Socket 网络编程

    Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页.QQ ...

  7. Python全栈【Socket网络编程】

    Python全栈[socket网络编程] 本章内容: Socket 基于TCP的套接字 基于UDP的套接字 TCP粘包 SocketServer 模块(ThreadingTCPServer源码剖析) ...

  8. python之Socket网络编程

    什么是网络? 网络是由节点和连线构成,表示诸多对象及其相互联系.在数学上,网络是一种图,一般认为专指加权图.网络除了数学定义外,还有具体的物理含义,即网络是从某种相同类型的实际问题中抽象出来的模型.在 ...

  9. Python之路【第七篇】python基础 之socket网络编程

    本篇文章大部分借鉴 http://www.cnblogs.com/nulige/p/6235531.html python socket  网络编程 一.服务端和客户端 BS架构 (腾讯通软件:ser ...

随机推荐

  1. CMMI过程改进反例

     近期一直在看CMMI的资料,越看认为越有意思.今天看到过程改进的时候,突然想起来之前所在的公司发生的过程改进相关的事儿来. 公司通过CMMI3级认证之后.PMO部门经理(公司还有质量管理部门经理 ...

  2. (转)php 根据url自动生成缩略图并处理高并发问题

    分享是一种精神,与技术高低无关!   图片缩略图动态生成- [代码编程] 2011-08-23 版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明http://www.blogbus.c ...

  3. ABAP HTTP POST

    1.HTTP DATA: lo_http_client TYPE REF TO if_http_client, lv_service TYPE string, lv_result TYPE strin ...

  4. nginx语法之location详解

    Location语法优先级排列 匹配符 匹配规则 优先级 = 精确匹配 ^~ 以某个字符串开头 ~ 区分大小写的正则匹配 ~* 不区分大小写的正则匹配 !~ 区分大小写不匹配的正则 !~* 不区分大小 ...

  5. [egret+pomelo]实时游戏杂记(2)

    [egret+pomelo]学习笔记(1) [egret+pomelo]学习笔记(2) [egret+pomelo]学习笔记(3) pomelo pomelo服务端介绍(game-server/con ...

  6. uboot中添加自定义命令

    uboot中可以通过修改源程序来添加自定义命令,进一步扩展uboot的功能. 我想在uboot下添加一条新的命令(名为varcpy),用来拷贝uboot中的环境变量. 修改方式如下: 创建新文件com ...

  7. 《C prime plus (第五版)》 ---第11章 字符串和字符串函数---2

    11-3:字符串 输出 三个标准的函数:puts() fputs() printf() 1.puts()函数: #include<stdio.h> #define DEF "I ...

  8. Java基础:hashCode与equals个人学习记录

    摘要: 本文主要记录本人对hashCode和对equals两个知识点的学习过程. 从学生时期初学java,就知道hashCode和equals这两个方法,工作中equals方法使用也是特别频繁,要说e ...

  9. npm使用淘宝镜像安装包

    npm使用registry这个属性指定仓库,因此配置这个属性即可.修改npm配置属性的几种方法详见官方文档. 这里只贴出修改registry的方法,以下三种任意一种即可: 修改~/.npmrc文件(没 ...

  10. MySQL Unable to convert MySQL date/time value to System.DateTime的解决办法

    在连接串中加入 Convert Zero Datetime=True