涉及到一些网络编程的基本概念,这里不做解释。
重点集中在用多进程实现,并且两次fork避免僵尸进程。主进程负责监听,孙进程负责与客户端交流。
实现的功能很简单,客户端连接成功后,输入一个整数,服务端返回它的二进制形式。客户端输入0,则主动退出。
服务端代码:
#include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <arpa/inet.h> #include <signal.h> #include <sys/wait.h> #include <stdlib.h> #define PORT 6666 #define SIZE 50 int Create_socket() //创建套接字和初始化以及监听函数 { int listen_socket = socket(AF_INET, SOCK_STREAM, 0); //创建一个套接字 if(listen_socket == -1) { perror("socket"); return -1; } struct sockaddr_in addr; bzero(&addr,sizeof(addr)); addr.sin_family = AF_INET; //Internet地址族 addr.sin_port = htons(PORT); //端口号,htons将主机字节序转为网络字节序 addr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址,服务器段不指定IP地址 int ret = bind(listen_socket, (struct sockaddr *)&addr, sizeof(addr)); //连接 if(ret == -1) { perror("bind"); return -1; } ret = listen(listen_socket, 5); //转变为监听套接字 if(ret == -1) { perror("listen"); return -1; } return listen_socket; } int wait_client(int listen_socket) { struct sockaddr_in cliaddr; int addrlen = sizeof(cliaddr); int client_socket = accept(listen_socket, (struct sockaddr *)&cliaddr, &addrlen);//得到和客户端交流的套接字 if(client_socket == -1) { perror("accept"); return -1; } printf("接收到一个客户端哈:%s\n",inet_ntoa(cliaddr.sin_addr)); return client_socket; } void talk_client(int client_socket) //与客户端交流,将客户端传来的数据处理 { char buf[SIZE]; while(1) { int ret = read(client_socket, buf, SIZE-1); if(ret == -1) { perror("read"); break; } if(ret == 0) { break; } buf[ret] = '\0'; int temp = atoi(buf); if(temp == 0) break; int i = 0; int count = 32; while(count--) { if(1<< count & temp ) buf[i++] = '1'; else buf[i++] = '0'; if(count %8 == 0) buf[i++] = ' '; } buf[i] = '\0'; printf("%s\n", buf); write(client_socket, buf, i+1); } printf("客户端退出啦哈\n"); close(client_socket); } int main() //主进程负责监听,子进程负责与客户端交流 { int listen_socket = Create_socket(); while(1) { int client_socket = wait_client(listen_socket); int pid = fork(); if(pid < 0) { perror("fail fork"); break; } else if(pid == 0)//子进程进来 { if(( pid = fork()) < 0) { perror("child process fail fork"); break; } else if (pid > 0) exit(0);//子进程退出,由init来接管孙进程,避免僵尸进程 talk_client(client_socket); //孙进程完成和客户端的交流 break; } else//主进程进来 { close(client_socket);//把主进程的交流套接字关掉,以免和孙进程冲突 } } close(listen_socket); return 0; }
客户端:
#include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <arpa/inet.h> #define PORT 6666 #define SIZE 50 int main() { int sockfd = socket(AF_INET,SOCK_STREAM,0); if(sockfd == -1) { perror("socket\n"); return -1; } struct sockaddr_in addr; bzero(&addr,sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(PORT); char c[] = "127.0.0.1"; inet_pton(AF_INET,c,(void *)&addr.sin_addr); int ret = connect(sockfd,(struct sockaddr*)&addr,sizeof(addr)); if(ret == -1) { perror("connect\n"); return -1; } printf("客户端连接成功了哈\n"); char buf[SIZE]; while(1) { printf("请输入你想输入的:"); scanf("%s",buf); write(sockfd,buf,strlen(buf)); if(atoi(buf) == 0) break; int ret = read(sockfd,buf,sizeof(buf)); if(ret == -1) { perror("read\n"); return -1; } buf[ret] = '\0'; printf("二进制形式:%s\n",buf); } close(sockfd); return 0; }