描述:关于tcp多用户的来链接问题:
首先需要了解select大致工作步骤:select是相当于一个等待函数,当参数中的集合里面的文件描述符有动作的时候,select函数会把有动作的文件描述符留下来,其余的全部清空掉,select的第三个参数,表示读
所以:
对于tcp的多用户的链接思路:
server端:将server_fd加入集合中,如果server_fd有动作就说明
有客户端想要链接,就调用accept函数。accept函数会把想要
链接的客户端的client_fd 返回,将client_fd放入一个数组中。
有多个链接的时候,把所有的都加入数组中。当其中的一个client_fd
有动作,就接收(recv)发过来的数据。运行一次集合都会清空保留一个,所以
在没有收到exit消息,要将client_fd数组里面的重新加入集合中。
如果收到exit消息,就将该文件描述符从数组中删除(数组中其余的文件描述符
往前移动)。
client端:正常发送接收消息即可。
ps:一般 写 ,不需要使用select,因为服务器写直接发送不需要客户端同意。
上述:可能看不懂,直接上代码,代码简易版大神勿喷
server端:
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char **argv)
{
//建立套接字
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == socket_fd)
{
perror("socket");
return -1;
}
//绑定本机的IP和端口
struct sockaddr_in saddr;
bzero(&saddr, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(atoi(argv[1]));
saddr.sin_addr.s_addr = inet_addr(argv[2]);
int ret = bind(socket_fd, (struct sockaddr *)&saddr, sizeof(saddr));
if(-1 == ret)
{
perror("bind");
return -1;
}
//设置为监听套接字
ret = listen(socket_fd, 4);
if(-1 == ret)
{
perror("listen");
return -1;
}
char buf[20] = {0};
fd_set set;
int max_fd = socket_fd;
int client_fd[20] = {0};
int num = 0;
struct timeval tv;
while(1)
{
FD_ZERO(&set);
FD_SET(socket_fd, &set);
max_fd = socket_fd;
for(int i =0; i<num; i++)
{
FD_SET(client_fd[i], &set);
max_fd = max_fd>client_fd[i]? max_fd:client_fd[i];
}
tv.tv_sec = 5; // 设置5秒时间超时时间
tv.tv_usec = 0; //必须加上微秒不然不行,最后的结果是两个相加,所以两个都要初始化设置
select(max_fd+1, &set, NULL, NULL, &tv);
if(FD_ISSET(socket_fd, &set))
{
//等待对端链接
client_fd[num++] = accept(socket_fd, NULL, NULL);
if(-1 == client_fd[num-1])
{
perror("accept");
return -1;
}
printf("connet %d\n", client_fd[num-1]);
}
for(int i=0; i<num; i++)
if(FD_ISSET(client_fd[i], &set))
{
bzero(buf, 20);
//read(client_fd, buf, 20);
recv(client_fd[i], buf, 20, 0);
printf("buf:%s\n", buf);
//退出处理
if(!strcmp(buf, "exit"))
{
printf("exit %d\n", client_fd[i]);
close(client_fd[i]);
//删除数组中对应的fd,并往前移动
for(int j = i; j<num; j++)
client_fd[j] = client_fd[j+1];
num--;
}
}
printf("%d\n", __LINE__);
}
for(int i = 0; i<num; i++)
close(client_fd[i]);
close(socket_fd);
}
client端:
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
//建立套接字
int client_fd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == client_fd)
{
perror("socket");
return -1;
}
//链接服务器
struct sockaddr_in saddr;
bzero(&saddr, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(atoi(argv[1]));
saddr.sin_addr.s_addr = inet_addr(argv[2]);
int ret = connect(client_fd, (struct sockaddr *)&saddr, sizeof(saddr));
if(-1 == ret)
{
perror("connect");
return -1;
}
//关闭读端
shutdown(client_fd, 0);
char buf[20] = {0};
while(1)
{
bzero(buf, 20);
scanf("%s", buf);
//write(client_fd, buf, 20);
printf("%d\n", __LINE__);
ret = send(client_fd, buf, 20, 0);
printf("ret:%d\n", ret);
if(-1 == ret)
{
perror("send");
return -1;
}
printf("buf:%s\n", buf);
if(!strcmp(buf, "exit"))
break;
}
ret = close(client_fd);
if(-1 == ret)
{
perror("close");
return -1;
}
}
代码确实有很多不完善的地方,但是功能没问题,因为刚学习linux网络编程,欢迎大神点评。