socket网络编程实践要点
Posted share-ideas
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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); if(sock_fd <= 0) { return false; } struct sockaddr_in client_addr= {0}; 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; if(::bind(sock_fd, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in))== -1) { close(sock_fd); sock_fd = -1; 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 long arg = 1; ioctlsocket(sock_fd, FIONBIO, &arg) ; ioctlsocket(sock_fd, FIONBIO, &arg) ; #endif #ifdef LINUX int arg = fcntl(sock_fd, F_GETFL, 0); 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) { int count = 0 ; ssize_t send_len = 0; do { if(count > 0) { sleep_ms(5*count); } //考虑网络不好时,需要尝试发送多次 send_len = sendto(socket_fd, buff, ssize_t(buff_len), 0, dest_addr, sizeof(struct sockaddr)); count++; }while(send_len <0 && errno == EAGAIN && count<=5); return int(send_len); }
3、发送udp广播包
int sendBroadUdpData(int sock_fd,char* buff,int buff_len) { // 将端口设置为允许广播包 int broadcast = 1; #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, 0, 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); char recv_buff[1024]; int recv_len = 0; recv_len = recvfrom(socket_fd, recv_buff, sizeof(recv_buff), 0, (struct sockaddr *)&client_addr, (socklen_t *)&len) if (recv_len > 0) { processMsg(recv_buff, recv_len, client_addr); } }
5、poll模型的构建,同时监控多个fd
{ int maxCount = 20; #ifdef LINUX struct pollfd wait_fd[maxCount]; #endif #ifdef WIN32 WSAPOLLFD wait_fd[maxCount]; #endif int real_count = 0; listen_fds.clear(); GetListenFd(listen_fds); for (int index = 0; 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 int res = ::poll(wait_fd, real_count, 100); //100毫秒超时 #endif #ifdef WIN32 int res = WSAPoll(wait_fd, real_count, 100); #endif if (res == -1) { usleep(10000); } else if (res) { int current_fd; for (int index = 0; index < real_count; index++) { current_fd = wait_fd[index].fd; if ((wait_fd[index].revents & POLLIN) > 0) { recvfrom(current_fd, recv_buff, sizeof(recv_buff), 0, (struct sockaddr *)&client_addr, (socklen_t *)&alen); bool is_listen_fd = false; //是否是监听句柄 for (int pos = 0; pos < (int)listen_fds.size(); pos++) { if (current_fd == listen_fds[pos]) { is_listen_fd = true; break; } } } if ((wait_fd[index].revents & POLLERR) > 0) usleep(10000); } } } else { printf("time out.\n"); } }
以上是关于socket网络编程实践要点的主要内容,如果未能解决你的问题,请参考以下文章
iOS网络编程实践--NSStream实现TCP Socket iPhone客户端