socket网络编程实践要点
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网络编程实践要点的更多相关文章
- Java之Socket网络编程实践
转自:http://my.oschina.net/leejun2005/blog/104955#comments 一.TCP/IP协议 既然是网络编程,涉及几个系统之间的交互,那么首先要考虑的是如何准 ...
- Socket 网络编程实践经验
目录 目录 相关文章 Socket 与 HTTP 的区别 生产实践考虑 网络断开重连问题 Heartbeat 心跳机制 使用非阻塞模式下的 select 函数进行 Socket 连接检查 会话过期问题 ...
- windows socket 网络编程
样例代码就在我的博客中,包含六个UDP和TCP发送接受的cpp文件,一个基于MFC的局域网聊天小工具project,和此小工具的全部执行时库.资源和执行程序.代码的压缩包位置是http://www.b ...
- Socket网络编程(案例)
Socket:套接字 java.net包 1.流式套接字:基于TCP协议的Socket网络编程 工作方式: 1.客户端A连接到服务器: 2.服务器建立连接并把客户端A添加到列表: 3.客户端B.C.. ...
- Linux Socket 网络编程
Linux下的网络编程指的是socket套接字编程,入门比较简单.在学校里学过一些皮毛,平时就是自学玩,没有见识过真正的socket编程大程序,比较遗憾.总感觉每次看的时候都有收获,但是每次看完了之后 ...
- Python Socket 网络编程
Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页.QQ ...
- Python全栈【Socket网络编程】
Python全栈[socket网络编程] 本章内容: Socket 基于TCP的套接字 基于UDP的套接字 TCP粘包 SocketServer 模块(ThreadingTCPServer源码剖析) ...
- python之Socket网络编程
什么是网络? 网络是由节点和连线构成,表示诸多对象及其相互联系.在数学上,网络是一种图,一般认为专指加权图.网络除了数学定义外,还有具体的物理含义,即网络是从某种相同类型的实际问题中抽象出来的模型.在 ...
- Python之路【第七篇】python基础 之socket网络编程
本篇文章大部分借鉴 http://www.cnblogs.com/nulige/p/6235531.html python socket 网络编程 一.服务端和客户端 BS架构 (腾讯通软件:ser ...
随机推荐
- Webpack探索【15】--- 基础构建原理详解(模块如何被组建&如何加载)&源码解读
本文主要说明Webpack模块构建和加载的原理,对构建后的源码进行分析. 一 说明 本文以一个简单的示例,通过对构建好的bundle.js源码进行分析,说明Webpack的基础构建原理. 本文使用的W ...
- Delphi 完全时尚手册之 Visual Style 篇
这里先说说两个概念:Theme(主题)和 Visual Style .Theme 最早出现在 Microsoft Plus! for Windows 95 中,是 Windows 中 Wallpape ...
- python cookbook第三版学习笔记二:字典
一般来说字典中是一个键对应一个单值的映射,如果想一个键值映射多个值,那么就需要将这些值放到另外的容器中,比如列表或者集合. 比如d={'a':[1,2]} Collections中的defaultdi ...
- [IR课程笔记]Query Refinement and Relevance Feedback
相关反馈的两种类型: “真实”的相关反馈: 1. 系统返回结果 2. 用户提供一些反馈 3. 系统根据这些反馈,返回一些不同的,更好的结果 “假定”的相关反馈 1. 系统得到结果但是并不返回结果 2. ...
- php 身份证号码获取星座和生肖
发布:thatboy 来源:Net [大 中 小] 本文介绍下,php用身份证号码获取星座和生肖的方法,一个简单的php实例,从身份证号码中取得星座与生肖信息,有兴趣的朋友参考研究下吧.本 ...
- mysql忘记root密码或报错:ERROR 1044 (42000): Access denied for user ”@’localhost’ to database ‘xx‘
有的时候忘记了root密码或其他用户的密码,登录的时候报错:ERROR 1044 (42000): Access denied for user ”@’localhost’ to database ' ...
- nodejs中的子进程,深入解析child_process模块和cluster模块
Node.js的进程管理 node遵循的是单线程单进程的模式,node的单线程是指js的引擎只有一个实例,且在nodejs的主线程中执行,同时node以事件驱动的方式处理IO等异步操作.node的 ...
- c语言学习的第13天1
#include <stdio.h> int main(void) { int a[5]={1,2,3,4,5}; printf("%#x, %#x\n",a,& ...
- BZOJ 1637 [Usaco2007 Mar]Balanced Lineup:前缀和 + 差分
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1637 题意: Farmer John 决定给他的奶牛们照一张合影,他让 N (1 ≤ N ...
- kvm初体验之二:安装
Host: CentOS release 6.4 (Final) 1. 开启处理器的虚拟化功能 进入BIOS,使能虚拟化功能: 进入linux, grep -E "vmx|svm" ...