LINUX下socket实现服务器与多客户端通信(一)

时间:2024-04-08 08:43:19

一直对网络方面的技术比较感兴趣,有时间就学习学习。虽然现在很多高级语言都已将网络编程部分做了封装处理,使之使用更加方便,但是学习基础原理,还是一个程序员必须要做的。

linux下的socket编程原理,网络上已经有大把的详细说明,这里不做说明,代码中已有简单注释。

具体方法,有不明白的,百度详情更能理解的彻底。

//服务端

#include<stdio.h>

#include<stdlib.h>

#include<errno.h>

#include<string.h>

#include<sys/types.h>

#include<netinet/in.h>

#include<sys/socket.h>

#include<sys/wait.h>

#define BUFFER_SIZE 100

//服务器读写方法

void listen_data(int fd,int id)

{

char buffer[BUFFER_SIZE];

while(1) //一直处于监听客户端信息状态,知道客户端断开或客户端发出退出信息

{

memset(buffer,0,BUFFER_SIZE);

int len = recv(fd,buffer,BUFFER_SIZE,0);

if(len > 0) //如果接受到数据,则判断是否为退出信息

{

if(strcmp(buffer,"exit\n") == 0)

{

printf("id %d exited.\n",id);

break;

}

printf("ID_%d:%s\n",id,buffer); //输出第N 个用户,输出的信息

}

else //接收数据小于0,或等于0 则退出

{

printf("clinet %d close!\n",id);

break;

}

//如果服务端需要发送信息,此处添加发送信息

//memset(buffer,0,BUFFER_SIZE);

//scanf("%s",buffer);

//send(fd,buffer,BUFFER_SIZE,0);

}

close(fd); //关闭此客户端的连接的socket

}


int main()

{

int sockfd,new_fd;

struct sockaddr_in my_addr; //本地连接socked

struct sockaddr_in their_addr; //客户端连接socked

int numbytes,sin_size;

char buffer[BUFFER_SIZE];

static int i=0; //记录连接客户端数目,可以使用数组,结构体等数据类型记录客户端信息(IP,端口等)

//记录本地信息

my_addr.sin_family = AF_INET; //IPV4

my_addr.sin_port = htons(9999); //绑定端口9999,并将其转化为网络字节

my_addr.sin_addr.s_addr = INADDR_ANY; //指定接收IP为任意(如果指定IP,则只接收指定IP)

bzero(&(my_addr.sin_zero),0); //最后位置赋0,补位置

//设置socked

if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)

{

perror("socket error!\n");

exit(1);

}

//绑定socked

if((bind(sockfd,(struct sockaddr_in*)&my_addr,sizeof(my_addr))) < 0)

{

perror("bind error!\n");

exit(1);

}

//开启监听,可连接客户端最大为10个

if(listen(sockfd,10) == -1)

{

perror("listen error!\n");

exit(1);

}

//服务端一直运行,等待客户端连接

while(1)

{

sin_size = sizeof(struct sockaddr_in);

//等待客户端连接,连接后their_addr接收客户端的IP等信息,没有客户端连接,则一直等待

if((new_fd = accept(sockfd,(struct sockaddr_in*)(&their_addr),&sin_size)) < 0)

{

perror("accept error!\n");

exit(1);

}

//连接成功后,连接客户端数+1

i++;

//开启进程运行客户端

pid_t childid;

childid = fork(); //fork()函数有两个返回值,0为子进程,-1为错。子进程运行客户端

if(childid == 0)

{

close(sockfd); //子进程中不再需要sockfd去监听,这里释放它,只需要new_fd即可

listen_data(new_fd,i);

exit(0);

}

//父进程继续执行while,在accept()等待客户端。父进程的socked此时还在运行,没有关闭

//此处没有设置父进程退出的代码,因为假设服务器一直运行,如果需要服务器自动退出,可设置服务器

//等待连接的时间,如果一定时间没有客户端连接,可以退出等待,结束

}

//所有客户端

close(sockfd);

printf("server-------closed.\n");

return 0 ;

}

//客户单代码

#include<stdio.h>

#include<stdlib.h>

#include<errno.h>

#include<string.h>

#include<sys/types.h>

#include<netinet/in.h>

#include<sys/socket.h>

#include<sys/wait.h>

 

int main()

{

int sockfd,numbytes;

char buff[100];

struct sockaddr_in their_addr;

int i=0;

 

their_addr.sin_family = AF_INET;

their_addr.sin_port = htons(9999);

their_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //本次设置的是本地连接

bzero(&(their_addr.sin_zero),0);

 

if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)

{

perror("socket error!\n");

exit(1);

}

 

// 使用connect连接服务器,their_addr获取服务器信息

if(connect(sockfd,(struct sockaddr*)&their_addr,sizeof(struct sockaddr)) == -1)

{

perror("connect error!\n");

exit(1);

}

 

while(1)

{

//连接成功后

memset(buff,0,sizeof(buff));

printf("clinet----:");

scanf("%s",buff);

//客户端开始写入数据,*****此处buff需要和服务器中接收

if(send(sockfd,buff,sizeof(buff),0) == -1)

{

perror("send error \n");

exit(1);

}

}

close(sockfd);

return 0;

}

 

运行效果如图:

LINUX下socket实现服务器与多客户端通信(一)

下一步,编写服务器客户端大文件传输和多客户端通信