1)server程序如下:
cpp
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#define BUFF_MAX 1024
// 英文小写转换成大写
static void str2up(char *str) {
while (*str) {
if (*str >= 'a' && *str <= 'z') {
*str = *str - 'a' + 'A';
}
str++;
}
}
int main(void) {
int server_sockfd, client_sockfd;
int server_len, client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
int result = 0;
fd_set readfds, writefds, rfds, wfds;
char buff[BUFF_MAX] = { '\0' };
// 建立服务器socket
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(9100);
server_len = sizeof(server_address);
// 绑定
bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
// 监听,最多监听10个
listen(server_sockfd, 10);
// 清零
FD_ZERO(&readfds);
FD_ZERO(&writefds);
// 将服务端socket加入到集合中
FD_SET(server_sockfd, &readfds);
FD_SET(server_sockfd, &writefds);
while (1) {
int fd;
int nread;
// 将需要监视的描述符集拷贝到select查询队列中,select会对其修改,所以一定要分开使用变量
rfds = readfds;
wfds = writefds;
printf("server waiting...\n");
// 无期限阻塞,并测试文件描述符变动
result = select(FD_SETSIZE, &rfds, &wfds, (fd_set *)0, (struct timeval *)0); // FD_SETSIZE,默认最大文件描述符,在这里最大是1024
if (result < 1) {
perror("select\n");
exit(1);
} else if (0 == result) {
printf("time out!\n");
}
// 扫描所有的文件描述符
for (fd = 0; fd < FD_SETSIZE; fd++) {
// 找到相关文件描述符,read
if (FD_ISSET(fd, &rfds)) {
// 判断是否为服务器套接字,是则表示客户端请求连接
//服务器描述符也是文件描述符的一种,也被加入到fd_set这个集合里面了。
//server_sockfd为服务器描述符," if (fd == server_sockfd)",这句话的意思是,服务器描述符有变化了(代表可读事件),肯定是有新的client添加进了。
if (fd == server_sockfd) {
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, (socklen_t*)(&client_len));
// 将客户端socket加入到集合中
FD_SET(client_sockfd, &readfds);
//FD_SET(client_sockfd, &writefds);
printf("adding client on fd %d\n", client_sockfd);
} else { // 客户端socket中有数据请求时
// 取得数据量交给nread
ioctl(fd, FIONREAD, &nread);
// 客户数据请求完毕,关闭套接字,从集合中清除相应描述符
if (0 == nread) {
close(fd);
FD_CLR(fd, &readfds); // 去掉g关闭的fd
printf("remove client on fd %d\n", fd);
} else {
read(fd, buff, BUFF_MAX);
sleep(5);
printf("receive:%s\n", buff);
printf("serving client on fd %d\n", fd);
FD_SET(client_sockfd, &writefds);
}
}
} else if (FD_ISSET(fd, &wfds)) {
str2up(buff); // 转化为大写
write(fd, buff, sizeof(buff));
memset(buff, 0, BUFF_MAX);
FD_CLR(fd, &writefds);
} else {
//printf("其他\n");
}
}
}
return 0;
}
2)client程序
cpp
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include<string.h>
#define BUFF_MAX 1024
int main(int argc, char **argv) {
int client_sockfd;
int len;
struct sockaddr_in address; // 服务器网络地址结构体
int result;
char buff[BUFF_MAX] = { '\0' };
if (argc < 2) {
fprintf(stderr, "missing parameter\n");
exit(1);
}
strcpy(buff, argv[1]);
// 建立客户端socket
client_sockfd = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("127.0.0.1");
address.sin_port = htons(9100);
len = sizeof(address);
// 连接服务器
result = connect(client_sockfd, (struct sockaddr *)&address, len);
if (-1 == result) {
perror("connect");
exit(1);
}
// 发送数据给服务器
write(client_sockfd, buff, strlen(buff));
memset(buff, '\0', BUFF_MAX);
// 接收服务器发回来的数据
read(client_sockfd, buff, BUFF_MAX);
printf("receive:%s\n", buff);
sleep(3);
close(client_sockfd);
return 0;
}
3)输出结果:
启动服务器程序:
./server
cpp
server waiting...
adding client on fd 4
server waiting...
receive:aaa
serving client on fd 4
server waiting...
server waiting...
remove client on fd 4
server waiting...
启动client程序:
./client hello
cpp
receive:AAA