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 ...
随机推荐
- Software-defined networking
Software-defined networking administrators to programmatically initialize, control, change, and mana ...
- Android之ProgressBar读取文件进度解析
ProgressBar进度条, 分为旋转进度条和水平进度条,进度条的样式根据需要自定义,之前一直不明白进度条如何在实际项目中使用,网上演示进度条的案例大多都是通过Button点 击增加.减少进度值,使 ...
- SlopeOne推荐算法
Slope One 算法 是一种基于评分的预测算法, 本质上也是一种基于项目的算法.与一般的基于项目的算法不同, 该算法不计算项目之间的相似度, 而是用一种简单的线性回归模型进行预测(可 ...
- 【linux】新添加一块硬盘制作LVM卷并进行分区挂载
linux服务器新添加一块硬盘,可以直接将盘格式化挂载就能用,比如挂载在/usr/local目录,但是这样有一个弊端,就是如果这一块磁盘满了,后续想要扩容的话,不能继续挂载这个/usr/local挂载 ...
- 2018年东北农业大学春季校赛 E wyh的阶乘 【数学】
题目链接 https://www.nowcoder.com/acm/contest/93/E 思路 其实就是找阶乘的项中5的个数 末尾为什么会出现0 因为存在5的倍数和偶数相乘 有0存在 借鉴 htt ...
- 《机器学习实战》学习笔记第十三章 —— 利用PCA来简化数据
相关博文: 吴恩达机器学习笔记(八) —— 降维与主成分分析法(PCA) 主成分分析(PCA)的推导与解释 主要内容: 一.向量內积的几何意义 二.基的变换 三.协方差矩阵 四.PCA求解 一.向量內 ...
- hdu 1042 N!(大数)
题意:求n!(0 ≤ N ≤ 10000) 思路:大数,用数组存储 1.首先要考虑数据N!的位数,因为最大是10000!,可以计算一下大概是5+9000*4+900*3+90*2+10*1=38865 ...
- elasticsearch-installation
1. 安装Java JDK 移步 :sdfa 2. 下载elasticsearch url : https://artifacts.elastic.co/downloads/elasticsearch ...
- python读文件出现中文乱码
更新: 一个解释更详细和全面的博文:https://www.cnblogs.com/zhangqigao/p/6496172.html 最近开始处理中文文本,读取文件有时候会出现乱码.原因:编码和解码 ...
- Java之动态代理简介
图截于<大话设计模式> Proxy模式是常用的设计模式,其特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等. 用户可以更 ...