IO多路tcp客户端

#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
#include<unistd.h>
#include<sys/select.h>
#define ERR_MSG(msg) do{\
	fprintf(stderr,"_%d_",__LINE__);\
    perror(msg);\
    }while(0)

#define PORT 8888 //1024~49151
#define IP "192.168.31.127"

int update_maxfd(int maxfd,fd_set readfds)
{
	int i=maxfd;
	for(;i>0;i++)
	{
		if(FD_ISSET(i,&readfds))
			return i;
	}
	return 0;
}
int main(int argc, const char *argv[])
{
	//创建流式套接字
	int sfd=socket(AF_INET,SOCK_STREAM,0);
	if(sfd<0)
	{
		ERR_MSG("socket");
		return -1;
	}
	printf("create socket success\n");



	// 填充地址信息结构体,真实的地址信息结构体与协议族相关
	struct sockaddr_in sin;
	sin.sin_family     =AF_INET;
	sin.sin_port       =htons(PORT);        //网络字节序的端口号
	sin.sin_addr.s_addr=inet_addr(IP);      //网络字节序的IP地址

  //连接服务器
  if (connect(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
  {
      ERR_MSG("connect");
      return -1;
  }
  printf("connect success\n");



	//创建一个读集合
	fd_set readfds;
	fd_set tempfds;
	//将集合清空
	FD_ZERO(&readfds);
	FD_ZERO(&tempfds);
	//将0号文件描述符添加到集合
	FD_SET(0,&readfds);
	//将sfd文件描述符添加
	FD_SET(sfd,&readfds);

	//最大文件描述符
	int maxfd=sfd;
	int select_res=0;
	char buf[128]="";
	ssize_t res=0;
	int i;
	//定义一个数组,存储每次连接成功的客户端的信息
	struct sockaddr_in save_addr[1024-4];
	while(1)
	{
		tempfds=readfds;
		select_res=select(maxfd+1,&tempfds,NULL,NULL,NULL);
		if(select_res<0)
		{
			ERR_MSG("select");
			return -1;
		}
		else if(select_res==0)
		{
			fprintf(stderr,"select time out\n");
			break;
		}
		//能运行到当前位置说明集合中文件描述符准备就绪
		//且集合只会剩下产生的文件描述符
		//例如,0号产生事件,则只会剩下0号

		for(i=0;i<=maxfd;i++)
		{
			if(FD_ISSET(i,&tempfds)==0)
			{
				continue;
			}

			if(i==0)
			{
				//触发键盘输入事件
				printf("触发键盘输入事件:");
				fflush(stdout);

				bzero(buf, sizeof(buf));

				//从终端获取文件描述符以及要发送的内容
				int sendfd;
				int res = scanf("%d %s", &sendfd, buf);
				while(getchar() != 10);
				if(res != 2)
				{
					fprintf(stderr, "请输入正确格式:文件描述符 要发送的内容\n");
					continue;
				}

				//判断获取到的文件描述符是否在readfds集合中
				if(FD_ISSET(sendfd, &readfds) == 0)
				{
					fprintf(stderr, "sendfd=%d 文件描述符不在集合中\n", sendfd);
					continue;
				}


				if(send(sendfd, buf, sizeof(buf), 0) < 0)
				{
					ERR_MSG("send");
					return -1;
				}
				printf("send message success\n");
			}
			else if(i==sfd)
			{
				printf("触发客户端连接事件:");
				fflush(stdout);


				//循环接收
				bzero(buf,sizeof(buf));
				size_t res=recv(i,buf,sizeof(buf),0);
				if(res<0)
				{
					ERR_MSG("recv");
					return -1;
				}
				else if(res ==0)
				{
					printf("[%s:%d] newfd=%d读取失败\n",inet_ntoa(sin.sin_addr),ntohs(sin.sin_port),i);
					//关闭文件描述符
					close(i);
					//将文件描述符从集合中剔除
					FD_CLR(i,&readfds);
					//更新maxfd
					maxfd=update_maxfd(maxfd,readfds);
				}
				else
				{
					printf("[%s:%d] newfd=%d %s\n",inet_ntoa(sin.sin_addr),ntohs(sin.sin_port),i,buf);
				}

			}
		}
	}
	close(sfd);


	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在Linux环境下使用C语言编写一个TCP服务器来处理多个客户端的连接是很常见的需求。以下是一个基本的实现示例: 首先,我们需要创建一个服务器套接字,监听指定的端口。然后,我们需要使用`select`函数来实现多客户端的处理。`select`函数会阻塞直到某个套接字上有可读或可写的数据时才返回,我们可以利用这一特性来处理多个客户端的连接。 为了支持多个客户端,我们需要维护一个客户端套接字的集合,用于存储当前连接的客户端。每当有新的客户端连接到服务器时,我们将其套接字添加到这个集合中。 然后,我们使用`select`函数来监视所有的套接字,包括服务器套接字和客户端套接字。当`select`函数返回时,我们可以通过检查文件描述符集合中的每个套接字来确定哪个套接字上有可读或可写的数据。如果是服务器套接字上有可读的数据,表示有新的客户端请求连接,我们接受这个连接并将其套接字添加到客户端集合中。如果是客户端套接字上有可读的数据,表示客户端发送了数据,我们可以处理这些数据。如果是客户端套接字上有可写的数据,表示服务器可以向客户端发送数据。 在处理数据时,我们可以使用`recv`函数来接收来自客户端的数据,然后根据实际需求进行处理,比如打印或保存数据。如果需要向客户端发送数据,可以使用`send`函数来发送数据。 以上就是基于Linux下C语言实现多客户端TCP服务器的基本思路。需要注意的是,在实际的代码实现中,还需要处理一些异常情况,例如客户端断开连接时的处理。此外,还可以使用多线程或多进程来处理多个客户端的同时连接,以提高服务器的性能和并发处理能力。 ### 回答2: 在Linux C中,可以使用TCP服务器来处理多个客户端连接。以下是一个简单的示例代码: 1. 首先,创建一个套接字(socket)来监听客户端连接请求: ```c int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { perror("socket"); exit(EXIT_FAILURE); } struct sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PORT); // 设置端口号 server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 监听所有网络接口 if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) { perror("bind"); exit(EXIT_FAILURE); } listen(sockfd, BACKLOG); // 启动监听 ``` 2. 使用循环等待客户端连接: ```c while(1) { struct sockaddr_in client_addr; socklen_t addr_len = sizeof(client_addr); int client_fd = accept(sockfd, (struct sockaddr*)&client_addr, &addr_len); if (client_fd == -1) { perror("accept"); exit(EXIT_FAILURE); } printf("Accept a connection from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); // 在接受到客户端连接后,可以fork()一个子进程来处理该客户端,或者使用线程、多路复用等方式来处理多个客户端 // ... } ``` 3. 在处理连接后,可以进行相应的数据交互,如接收和发送数据,以及关闭连接等操作。 ```c // 读取客户端发送的数据 char buffer[MAX_BUFFER_SIZE]; int num_bytes = recv(client_fd, buffer, sizeof(buffer), 0); if (num_bytes == -1) { perror("recv"); exit(EXIT_FAILURE); } // 处理数据 // ... // 发送响应给客户端 char response[] = "Hello, client!"; if (send(client_fd, response, sizeof(response), 0) == -1) { perror("send"); exit(EXIT_FAILURE); } // 关闭与客户端的连接 close(client_fd); ``` 这是一个简单的多客户端TCP服务器的实现代码。当然,在实际应用中,可能需要处理更多的异常情况,如错误处理、客户端连接超时、并发访问等。同时,还可以使用线程池、epoll等技术来提高服务器的性能和并发处理能力。 ### 回答3: 在Linux C编程中,可以通过创建一个TCP服务器来处理多个客户端的连接请求。 首先,我们需要创建一个套接字,使用`socket()`函数,指定使用TCP协议,得到一个用于监听的套接字描述符。 ```c int serverSocket = socket(AF_INET, SOCK_STREAM, 0); ``` 然后,我们需要给服务器绑定一个地址和端口号,使用`bind()`函数,将套接字与特定的IP地址和端口号绑定。 ```c struct sockaddr_in serverAddress; serverAddress.sin_family = AF_INET; serverAddress.sin_port = htons(PORT); serverAddress.sin_addr.s_addr = INADDR_ANY; bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)); ``` 接下来,我们需要设置服务器监听队列的最大长度,使用`listen()`函数。 ```c listen(serverSocket, BACKLOG); ``` 现在,我们正式进入了服务器的工作循环,接受客户端的连接请求。 ```c while(1) { int clientSocket = accept(serverSocket, NULL, NULL); // 这里可以创建子进程或线程来处理客户端的连接 // 或使用非阻塞IO或异步IO来实现并发处理多个客户端 // 读取客户端发送的数据 char buffer[BUFFER_SIZE]; int bytesRead = recv(clientSocket, buffer, sizeof(buffer), 0); // 处理接收到的数据 // 发送数据给客户端 char response[] = "Hello, client!"; send(clientSocket, response, strlen(response), 0); // 关闭与客户端的连接 close(clientSocket); } ``` 以上就是一个简单的Linux C TCP服务器客户端的实现。在实际应用中,可能需要使用多线程、多进程、非阻塞IO或者异步IO等技术来提高服务器的并发处理能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值