Linux C selete函数实现echo服务器

开发环境VS2019+ VMware Unbuntu18

注意仔细体会linux selete 函数的使用过程。select函数是基于轮询的过程。

服务器

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/select.h>

const int BUF_SIZE = 100;
void error_handing(char* message);

int main()
{ 
	int serv_sock;                      // 服务器sock
	int clnt_sock;                      // 客户端sock
	struct sockaddr_in serv_addr;       // 服务器地址
	struct sockaddr_in clnt_addr;       // 客户端地址
	// 创建
	serv_sock = socket(PF_INET, SOCK_STREAM, 0);
	if (serv_sock == -1)
		error_handing("socket() error");
	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = 18888;                 // 端口
	serv_addr.sin_addr.s_addr = INADDR_ANY;    // ip
	// 绑定
	if (bind(serv_sock, (struct sockaddr*) & serv_addr, sizeof(serv_addr)) == -1)
		error_handing("bind() error");
	// 监听
	if (listen(serv_sock, 5) == -1)
		error_handing("listen() error");

	fd_set reads, cpy_reads;           // select函数中fd_set 结构体
	struct timeval timeout;            // select函数中阻塞等待时间参数

	FD_ZERO(&reads);                   // 初始化fd_set结构体
	FD_SET(serv_sock, &reads);         // 将服务器sock放到结构体中
	int fd_max = serv_sock;            // 文件描述符

	while (1) {
		cpy_reads = reads;             // 重新设置fd_set
		timeout.tv_sec = 1;            // 重新设置时间
		timeout.tv_usec = 0;

		int fd_num;
		if ((fd_num = select(fd_max + 1, &cpy_reads, 0, 0, &timeout)) == -1)
			break;
		if (fd_num == 0)
			continue;

		// 开始轮询
		for (int i = 0; i < fd_max + 1; i++) {
			if (FD_ISSET(i, &cpy_reads)) {  
				if (i == serv_sock) {
					socklen_t adr_sz = sizeof(clnt_addr);
					clnt_sock = accept(serv_sock, (struct sockaddr*) & clnt_addr, &adr_sz);
					FD_SET(clnt_sock, &reads);
					if (fd_max < clnt_sock)
						fd_max = clnt_sock;
					printf("connected client: %d \n", clnt_sock);
				}
				else {
					char buf[BUF_SIZE];
					int str_len = read(i, buf, BUF_SIZE);
					if (str_len == 0) {
						FD_CLR(i, &reads);          // 说明客户端已断开连接
						close(i);
						printf("closed client: %d \n", i);
					}
					else 
						write(i, buf, str_len);
				}
			}
		}
	}
	close(serv_sock);
	return 0;
}

void error_handing(char* message)
{
	fputs(message, stderr);
	fputs("\n", stderr);
	exit(1);
}

客户端

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
const int  BUF_SIZE = 1024;
void error_handing(char* message);


int main()
{
	int sock;
	struct sockaddr_in serv_addr;
	// 创建socket
	sock = socket(PF_INET, SOCK_STREAM, 0);
	if (sock == -1)
		error_handing("socket() error");
	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = 18888;                 // 端口
	serv_addr.sin_addr.s_addr = INADDR_ANY;    // ip
	if (connect(sock, (struct sockaddr*) & serv_addr, sizeof(serv_addr)) == -1)
		error_handing("connect() error");
	else
		puts("Connected...");

	while (1) {
		fputs("Input message(Q to quit): ", stdout);
		char message[BUF_SIZE];
		fgets(message, BUF_SIZE, stdin);
		if (!strcmp(message, "q\n") || !strcmp(message, "Q\n"))
			break;               // 按q或Q退出,其他发送字符串
		write(sock, message, strlen(message));
		int str_len = read(sock, message, BUF_SIZE);
		message[str_len] = '\0';
		printf("Message from server: %s", message);
	}
	close(sock);
	return 0;
}

void error_handing(char* message)
{
	fputs(message, stderr);
	fputs("\n", stderr);
	exit(1);
}

猜你喜欢

转载自blog.csdn.net/wwxy1995/article/details/94401220