一直对网络方面的技术比较感兴趣,有时间就学习学习。虽然现在很多高级语言都已将网络编程部分做了封装处理,使之使用更加方便,但是学习基础原理,还是一个程序员必须要做的。
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;
}
运行效果如图:
下一步,编写服务器客户端大文件传输和多客户端通信