socket非阻塞客户端
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <stdio.h>
#include <sys/socket.h>
#include <string.h>
#include <signal.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
//客户端非阻塞
typedef struct MySocketInfo{
int socketCon;
unsigned long ipaddr;
unsigned short port;
}_MySocketInfo;
void *fun_thrReceiveHandler(void *socketCon);
int main()
{
printf("开始socket\n");
int socketCon = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in server_addr;
bzero(&server_addr,sizeof(struct sockaddr_in));
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
server_addr.sin_port=htons(1000);
int flags =fcntl(socketCon,F_GETFL,0); //得到套接字描述符标志位
if(flags<0)
{
printf("获取套接字描述符标志位失败\n");
exit(-1);
}
else
{
printf("得到套接字描述符标志位flags=%d\n",flags);
}
// flags=0;
// int flagst=0;
int flagst= fcntl(socketCon,F_SETFL,flags|O_NONBLOCK);//更改套接字描述符标志位
if(flagst<0)
{
printf("更改套接字描述符失败\n");
printf("flagst=%d",flagst);
// exit(-1);
}
else
{
printf("更改套接字描述符标志成功flagst=%d\n",flagst);
}
// struct timeval svTimeout;
// svTimeout.tv_sec=5;
// svTimeout.tv_usec=0;
// int setsocktmp1=setsockopt(socketCon, SOL_SOCKET, SO_SNDTIMEO, (char *)&svTimeout, sizeof(struct timeval));
// int setsocktmp2= setsockopt(socketCon, SOL_SOCKET, SO_RCVTIMEO, (char *)&svTimeout, sizeof(struct timeval));
int res_con = connect(socketCon,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr));
if( res_con==0)
{
printf("连接的套接字res_con=%d\n",res_con);
sleep(10);
}
else if((res_con<0)&&(errno!= EINPROGRESS))
{
printf("连接建立失败\n");
printf("errno=%d",errno);
printf("error:%s\n",strerror(errno));
}
else if((res_con<0)&&(errno== EINPROGRESS))
{
printf("连接已建立但连接未成功\n");
printf("errno=%d",errno);
printf("error:%s\n",strerror(errno));
fd_set writeset;//申明一个集合来保存要检测的套接字
FD_ZERO(&writeset);//集合清零
FD_SET(socketCon,&writeset);//要检测的套接字放在集合中
struct timeval stTimeout;
stTimeout.tv_sec=1;
stTimeout.tv_usec=0;
// int res=-1;
int res =select(socketCon+1,NULL,&writeset,NULL,&stTimeout);
if(res<0)
{
printf("select出错\n");
printf("errno=%d",errno);
printf("error:%s\n",strerror(errno));
}
else if(res>0)
{
printf("时间未到被监控套接字状态发生改变\n");
printf("res=%d\n",res);
printf("errno=%d",errno);
printf("error:%s\n",strerror(errno));
if(FD_ISSET(socketCon,&writeset))
{
int error=0;
socklen_t len =sizeof(error);
if(getsockopt(socketCon,SOL_SOCKET,SO_ERROR ,&error ,&len)==-1)
{
printf("建立连接失败\n");
printf("errno=%d",errno);
printf("error:%s\n",strerror(errno));
}
else //成功返回零
{
printf("建立连接成功\n");
printf("errno=%d",errno);
printf("error:%s\n",strerror(errno));
}
}
}
else
{
printf("超时\n");
printf("errno=%d",errno);
printf("error:%s\n",strerror(errno));
}
}
pthread_t thrReceive;
pthread_create(&thrReceive,NULL,fun_thrReceiveHandler,&socketCon);
pthread_detach(thrReceive);
while(1)
{
char userStr[300] = {'0'};
scanf("%s",userStr);
if(strcmp(userStr,"q") == 0)
{
printf("退出!\n");
}
// 发送消息
int sendMsg_len = send(socketCon,userStr,300,0);
if(sendMsg_len > 0)
{
printf("发送成功,服务端套接字:%d\n",socketCon);
}else
{
printf("发送失败\n");
}
}
close(socketCon);
return 0;
}
void *fun_thrReceiveHandler(void *socketCon)
{
pthread_detach(pthread_self());//子线程自己分离自己线程
while(1)
{
char buffer[30];
int _socketCon = *((int *)socketCon);
int buffer_length = recv(_socketCon,buffer,300,MSG_DONTWAIT);
if(buffer_length == 0)
{
printf("服务器端异常关闭\n");
printf("errno=%d",errno);
printf("error:%s\n",strerror(errno));
}
else if(buffer_length < 0)
{
printf("接受服务器数据失败\n");
printf("errno=%d",errno);
printf("error:%s\n",strerror(errno));
}
else
{
printf("接受到数据\n");
// printf("buffer_length=%d \n",buffer_length);
printf("errno=%d",errno);
printf("error:%s\n",strerror(errno));
buffer[buffer_length] = '\0';
printf("服务器说:%s\n",buffer);
memset(&buffer,0,sizeof(buffer));
}
printf("进入非阻塞测试\n");
sleep(1);
}
return NULL;
}
非阻塞型服务器
#include <stdlib.h>
#include <sys/types.h>
#include <stdio.h>
#include <sys/socket.h>
#include <string.h>
#include <signal.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
//服务器端非阻塞
void *fun_thrReceiveHandler(void *socketInfo);
void *fun_thrAcceptHandler(void *socketListen);
//void *fun_id(void*on);
void setsocketunlock(int sock);
void fun_socket();
typedef struct MySocketInfo
{
int socketCon;
char *ipaddr;
uint16_t port;
}_MySocketInfo;
// 客户端数组
struct MySocketInfo arrConSocket[10];
int conClientCount = 0;
// 接受客户端线程列表
pthread_t arrThrReceiveClient[10];
int thrReceiveClientCount = 0;
int main()
{
int on=1;
printf("开始socket\n");
//创建套接字
int socketListen = socket(AF_INET, SOCK_STREAM, 0);
// printf("socketListen= %d\n" ,socketListen);
if(socketListen < 0)
{
printf("创建失败\n");
exit(-1);
}
else
{
printf("创建套接字成功\n");
}
//通讯准备
struct sockaddr_in server_addr;
bzero(&server_addr,sizeof(struct sockaddr_in));
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
server_addr.sin_port=htons(2000);
int temp=1;
int socketset3= setsockopt(socketListen, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(temp));
if(socketset3<0)
{
perror("setsockopt");
exit(-1);
}
//本地地址与套接口捆绑
if(bind(socketListen, (struct sockaddr *)&server_addr,sizeof(struct sockaddr)) != 0)
{
perror("绑定本地ip地址、端口号失败\n");
exit(-1);
}
else
{
printf("绑定本地ip地址,端口号成功\n");
}
// 将套接字设为监听模式,等待队列最大长度为10
if(listen(socketListen, 10) != 0){
printf("开启监听失败\n");
exit(-1);
}
else
{
printf("开启监听成功\n");
}
pthread_t thrAccept;
pthread_create(&thrAccept,NULL,fun_thrAcceptHandler,&socketListen);
pthread_detach(thrAccept );//子线程与父线程分离开
while(1)
{
printf("当前有接受数据线程多少个:%d\n",thrReceiveClientCount);
//向客户端发送数据
char userStr[30] = {'0'};
scanf("%s",userStr);
// 退出
if(strcmp(userStr,"q") == 0)
{
printf("用户选择退出!\n");
break;
}
if(conClientCount <= 0)
{
printf("没有客户端连接\n");
}
else
{
int i;
for(i=0; i<conClientCount; i++)
{
//把输入内容写入发送客户端的数组中
int sendMsg_len = send(arrConSocket[i].socketCon,userStr,300,0);
// printf("发送客户端的数据最大字节数:%d\n", sendMsg_len);
if(sendMsg_len > 0)
{
printf("向%s:%d发送成功\n",arrConSocket[i].ipaddr,arrConSocket[i].port);
}
else
{
printf("向%s:%d发送失败\n",arrConSocket[i].ipaddr,arrConSocket[i].port);
}
}
}
sleep(0.5);
}
return 0;
}
//将套接字设置为非阻塞
void setsocketunlock(int sock)
{
int flags=fcntl(sock,F_GETFL,0);
if(flags<0)
{
printf("获取套接字描述符标志位失败\n");
}
int flagst=fcntl(sock,F_SETFL,flags|O_NONBLOCK);
if(flagst<0)
{
printf("更改套接字描述符失败flagst=%d\n",flagst);
}
else
{
printf("更改套接字描述符成功flagst=%d\n",flagst);
}
}
void *fun_thrAcceptHandler(void *socketListen)
{
while(1)
{
int sockaddr_in_size = sizeof(struct sockaddr_in);
struct sockaddr_in client_addr;
bzero(&client_addr,sizeof(struct sockaddr_in));
int _socketListen = *((int *)socketListen);
printf("_socketListen=%d\n",_socketListen);
//创建一个与客户端连接的套接字
// int socketCon = accept4(_socketListen, (struct sockaddr *)(&client_addr), (socklen_t *)(&sockaddr_in_size),SOCK_NONBLOCK);
// int socketCon = accept(_socketListen, (struct sockaddr *)(&client_addr), (socklen_t *)(&sockaddr_in_size));
setsocketunlock(_socketListen);
int socketCon = accept(_socketListen, (struct sockaddr *)(&client_addr), (socklen_t *)(&sockaddr_in_size));
if(socketCon<0)
{
if(errno==EAGAIN)
{
printf("接受连接请求已经建立但未成功\n");
}
else if(errno!=EAGAIN)
{
printf("接受连接请求建立失败\n");
}
}
fd_set writeset;
FD_ZERO(&writeset);
FD_SET(socketCon,&writeset);
struct timeval stTimeout;
stTimeout.tv_sec=5;
stTimeout.tv_usec=0;
int res =select(socketCon+1,NULL,&writeset,NULL,&stTimeout);
if(res>0)
{
printf("时间未到被监控套接字状态发生改变\n");
printf("res=%d\n",res);
printf("errno=%d",errno);
printf("error:%s\n",strerror(errno));
if(FD_ISSET(socketCon,&writeset))
{
int error=0;
socklen_t len =sizeof(error);
if(getsockopt(socketCon,SOL_SOCKET,SO_ERROR ,&error ,&len)==-1)
{
printf("连接失败\n");
printf("errno=%d",errno);
printf("error:%s\n",strerror(errno));
}
else //成功返回零
{
printf("连接成功\n");
printf("连接的客户端套接字socketCon=%d\n",socketCon);
printf("errno=%d",errno);
printf("error:%s\n",strerror(errno));
}
}
}
else if(res<0)
{
printf("select出错\n");
printf("errno=%d",errno);
printf("error:%s\n",strerror(errno));
//错误类型为非法参数
}
else
{
printf("超时,被监控的套接字文件不可写\n");
printf("errno=%d",errno);
printf("error:%s\n",strerror(errno));
}
_MySocketInfo socketInfo;
socketInfo.socketCon = socketCon;
socketInfo.ipaddr = inet_ntoa(client_addr.sin_addr);
socketInfo.port = client_addr.sin_port;
arrConSocket[conClientCount] = socketInfo;
pthread_t thrReceive = 0;
pthread_create(&thrReceive,NULL,fun_thrReceiveHandler,&socketInfo);
pthread_detach(thrReceive);
arrThrReceiveClient[thrReceiveClientCount] = thrReceive;
thrReceiveClientCount++;
conClientCount++;
sleep(0.5);
}
sleep(2);
}
//接收客户端发来的数据
void *fun_thrReceiveHandler(void *socketInfo)
{
char buffer[30];
int buffer_length;
_MySocketInfo _socketInfo = *((_MySocketInfo *)socketInfo);
// setsocketunlock(_socketInfo.socketCon);
while(1)
{
bzero(&buffer,sizeof(buffer));
//读取出来的数据放在缓存区中
buffer_length = recv(_socketInfo.socketCon,buffer,300,0);
if(buffer_length == 0)
{
printf("%s:%d 客户端关闭\n",_socketInfo.ipaddr,_socketInfo.port);
printf("errno=%d",errno);
printf("error:%s\n",strerror(errno));
conClientCount--;
break;
}
else if(buffer_length < 0)
{
printf("errno=%d",errno);
printf("error:%s\n",strerror(errno));
if(errno==EAGAIN)
{
printf("接受客户端数据失败\n");
}
}
else if(buffer_length>0)
{
buffer[buffer_length] = '\0';
printf("%s:%d 说:%s\n",_socketInfo.ipaddr,_socketInfo.port,buffer);
}
printf("进入非阻塞测试\n");
sleep(2);
}
return NULL;
}