select() 函数主要是建立在fd_set类型的基础上
1. 操作宏
fd_set set;
FD_ZERO(&set); 将 set 清零使集合中不含任何fd
FD_SET(fd, &set); 将 fd 加入 set 集合
FD_CLR(fd, &set); 将 fd 从 set 集合中清除
FD_ISSET(fd, &set); 测试 fd 是否在 set 集合中
2. 函数说明
int select(int nfds, fd_set *readset, fd_set *writeset, fd_set* exceptset, struct timeval *timeout);
测试指定的 fd 可读?可写?有异常条件待处理?
参数
nfds : 需要检查的文件描述字个数, 三组 fd_set 中所含的最大 fd 值加 1
readset : 结构体指针, 检查可读性的一组文件描述字
writeset : 结构体指针, 检查可写性的一组文件描述字
exceptset: 结构体指针, 检查是否有异常条件出现的文件描述字 (错误不包括在异常条件之内)
timeout : 结构体指针, 三种可能
1. timeout=NULL (阻塞, 直到有一个 fd 状态变化函数才返回)
2. timeout=结构体设为非零 (阻塞, 等待固定时间, 有一个 fd 状态变化或者时间耗尽, 函数均返回)
3. timeout=结构体时间设为 0 (非阻塞, 函数检查完每个 fd 后立即返回))
返回值
< 0: 错误
= 0: 超时
> 0: 返回状态变化的 fd 总数
3. 使用实例
3-1. 服务器
--
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#include<sys/socket.h>
#include<sys/un.h>
#include<unistd.h>
char buffer[1024];
void *pthread_function(void *arg);
pthread_mutex_t work_mutex;
int main()
{
int result;
struct sockaddr_un server_address, client_address;
int client_len;
int server_socketfd, client_socketfd;
pthread_t a_thread;
result = pthread_mutex_init(&work_mutex, NULL);
if(result != 0) {
perror("pthread_mutex_init");
exit(EXIT_FAILURE);
}
server_socketfd = socket(AF_UNIX, SOCK_STREAM, 0);
server_address.sun_family = AF_UNIX;
strcpy(server_address.sun_path, "server_socket");
unlink("server_socket");
result = bind(server_socketfd, (struct sockaddr*)&server_address, sizeof(server_address));
if(result != 0) {
perror("bind");
exit(EXIT_FAILURE);
}
result = listen(server_socketfd, 5);
if(result != 0) {
perror("listen");
exit(EXIT_FAILURE);
}
client_len = sizeof(client_address);
while(1) {
client_socketfd = accept(server_socketfd, (struct sockaddr*)&client_address, &client_len);
result = pthread_create(&a_thread, NULL, pthread_function, (void *)client_socketfd);
if(result != 0) {
perror("pthread_create");
exit(EXIT_FAILURE);
}
}
}
void *pthread_function(void *arg)
{
int fd = (int) arg;
int result;
fd_set read_fds;
int max_fds;
struct timeval timeout = {3, 0};
printf("%d id has connected!!\n", fd);
while (1) {
FD_ZERO(&read_fds);
FD_SET(0, &read_fds);
FD_SET(fd, &read_fds);
max_fds = fd + 1;
pthread_mutex_lock(&work_mutex);
printf("[server local] %d has get the lock\n", fd);
result = select(max_fds, &read_fds, (fd_set *)NULL, (fd_set *)NULL, &timeout);
if(result < 1) {
printf("select");
}
if(FD_ISSET(0, &read_fds)) {
memset(buffer, '\0', sizeof(buffer));
fgets(buffer, sizeof(buffer), stdin);
if((strncmp("quit", buffer, 4))==0) {
printf("[server local] You have terminaled the chat!\n");
pthread_mutex_unlock(&work_mutex);
break;
} else {
result = write(fd, buffer, sizeof(buffer));
if(result == -1) {
perror("write");
exit(EXIT_FAILURE);
}
}
}
if(FD_ISSET(fd, &read_fds)) {
memset(buffer, '\0', sizeof(buffer));
result = read(fd, buffer, sizeof(buffer));
if(result == -1) {
perror("read");
exit(EXIT_FAILURE);
} else if(result == 0) {
printf("[from client] client has terminal the chat!\n");
pthread_mutex_unlock(&work_mutex);
break;
} else {
printf("[from client] receive message: %s", buffer);
}
}
pthread_mutex_unlock(&work_mutex);
usleep (1000 * 100 * 5);
}
close(fd);
pthread_exit(NULL);
}
================================================================================
3-2. 客户端
--
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<sys/un.h>
#include<string.h>
#include<sys/types.h>
#include<sys/time.h>
int main()
{
int result;
int socketfd;
int len;
struct sockaddr_un address;
fd_set read_fds, test_fds;
int fd;
int max_fds;
char buffer[1024];
socketfd = socket(AF_UNIX, SOCK_STREAM, 0);
address.sun_family = AF_UNIX;
strcpy(address.sun_path, "server_socket");
len = sizeof(address);
result = connect(socketfd, (struct sockaddr*)&address, len);
if(result == -1) {
perror("connect");
exit(EXIT_FAILURE);
}
FD_ZERO(&read_fds);
FD_SET(0, &read_fds);
FD_SET(socketfd, &read_fds);
max_fds = socketfd +1;
printf("Chat now!!\n");
while(1) {
test_fds = read_fds;
result = select(max_fds, &test_fds, (fd_set *)NULL, (fd_set *)NULL, (struct timeval*)NULL);
if(result < 1) {
perror("select");
exit(EXIT_FAILURE);
}
if(FD_ISSET(0, &test_fds)) {
memset(buffer, '\0', sizeof(buffer));
fgets(buffer, sizeof(buffer), stdin);
if((strncmp("quit", buffer, 4))== 0) {
printf("\n[client local] You are going to quit!\n");
break;
}
result = write(socketfd, buffer, sizeof(buffer));
if(result == -1) {
perror("write");
exit(EXIT_FAILURE);
}
}
if(FD_ISSET(socketfd, &test_fds)) {
memset(buffer, '\0', sizeof(buffer));
result = read(socketfd, buffer, sizeof(buffer));
if(result == -1) {
perror("read");
exit(EXIT_FAILURE);
} else if(result == 0) {
printf("[from server] server has termianl chat!\n");
break;
} else {
printf("[from server] recieve message: %s", buffer);
}
}
}
close(socketfd);
exit(EXIT_SUCCESS);
}
0 件のコメント:
コメントを投稿