1.服务端程序:
需要注意的是启动一个子进程是在接收(accept)一个新连接后
代码如下:
void handle(int sockfd,struct sockaddr_in cli_addr)
{
while(1)
{
char buff[1024]={0};
recv(sockfd,buff,1023,0);
printf("client:%s:%d say:%s\n",
inet_ntoa(cli_addr.sin_addr),
ntohs(cli_addr.sin_port),
buff);
}
return;
}
int create_worker(int sockfd,struct sockaddr_in cli_addr)
{
int pid=-1;
pid=fork();
if(pid<0){
close(sockfd);
return -1;
}
else if(pid==0){
//如果子进程一直运行,那么父进程就会阻塞在wait
//所以需要创建孙子进程,让孙子进程来处理客户端数据
if(fork()==0){
handle(sockfd,cli_addr);
}
exit(0);
}
else{
wait(NULL);
close(sockfd);
}
return 0;
}
int main(int argc,char *argv[])
{
if(argc!=3){
printf("Usage: fdTCP_server ip port\n");
return -1;
}
int sockfd=-1;
sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(sockfd<0){
perror("socket error");
return -1;
}
//绑定地址信息
struct sockaddr_in server_addr;
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(atoi(argv[2]));//htons是将主机字节序转变成网络字节序
server_addr.sin_addr.s_addr=inet_addr(argv[1]);//inet_addr是将点分十进制的IP地址转换为网络字节序
socklen_t len=sizeof(struct sockaddr_in);
int ret=bind(sockfd,(struct sockaddr*)&server_addr,len);
if(ret<0){
perror("bind error!");
return -1;
}
//监听
if(listen(sockfd,5)<0){
perror("listen error!");
return -1;
}
//接收请求
while(1){
int new_fd;
struct sockaddr_in cli_addr;
new_fd=accept(sockfd,(struct sockaddr*)&cli_addr,&len);
if(new_fd<0){
perror("accept error");
return -1;
}
//接收新请求后,子进程开始工作
create_worker(new_fd,cli_addr);
}
return 0;
}
2.客户端
和TCP客户端程序基本一样