www.pudn.com > linuxsocket.rar > my_server.c
// Client/Server模型的服务器端 #include#include #include #include #include #include #include #include #include "my_recv.h" // 自定义的头文件 #define SERV_PORT 4507 // 服务器端的端口 #define LISTENQ 12 // 连接请求队列的最大长度 #define INVALID_USERINFO 'n' // 用户信息无效 #define VALID_USERINFO 'y' // 用户信息有效 #define USERNAME 0 // 接收到的是用户名 #define PASSWORD 1 // 接收到的是密码 struct userinfo { // 保存用户名和密码的结构体 char username[32]; char password[32]; }; struct userinfo users[ ] = { {"linux", "unix"}, {"4507", "4508"}, {"clh", "clh"}, {"xl", "xl"}, {" "," "} // 以只含一个空格的字符串作为数组的结束标志 }; // 查找用户名是否存在,存在返回该用户名的下标,不存在则返回-1,出错返回-2 int find_name(const char *name) { int i; if (name == NULL) { printf("in find_name, NULL pointer"); return -2; } for (i=0; users[i].username[0] != ' ';i++) { if (strcmp(users[i].username, name) == 0) { return i; } } return -1; } // 发送数据 void send_data(int conn_fd, const char *string) { if (send(conn_fd, string, strlen(string), 0) < 0) { my_err("send", __LINE__); // my_err函数在my_recv.h中声明 } } int main() { int sock_fd, conn_fd; int optval; int flag_recv = USERNAME; // 标识接收到的是用户还是密码 int ret; int name_num; pid_t pid; socklen_t cli_len; struct sockaddr_in cli_addr, serv_addr; char recv_buf[128]; // 创建一个TCP套接字 sock_fd = socket(AF_INET, SOCK_STREAM,0); if (sock_fd < 0) { my_err("socket", __LINE__); } // 设置该套接字使之可以重新绑定端口 optval = 1; if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&optval, sizeof(int)) < 0) { my_err("setsockopt", __LINE__); } // 初始化服务器端地址结构 memset(&serv_addr, 0, sizeof (struct sockaddr_in)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(SERV_PORT); serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 将套接字绑定到本地端口 if (bind(sock_fd, (struct sockaddr *)&serv_addr, sizeof (struct sockaddr_in)) < 0) { my_err("bind", __LINE__); } // 将套接字转化为监听套接字 if (listen(sock_fd, LISTENQ) < 0) { my_err("listen", __LINE__); } cli_len = sizeof (struct sockaddr_in); while (1) { // 通过accept接受客户端的连接请求,并返回连接套接字用于收发数据 conn_fd = accept(sock_fd, (struct sockaddr *)&cli_addr, &cli_len); if (conn_fd < 0) { my_err("accept", __LINE__); } printf("accept a new client, ip:%s\n", inet_ntoa(cli_addr.sin_addr)); // 创建一个子进程处理刚刚接受的连接请求 if ( (pid = fork()) == 0 ) { // 子进程 while(1) { if ((ret = recv(conn_fd, recv_buf, sizeof (recv_buf), 0)) < 0) { perror("recv"); exit(1); } recv_buf[ret-1] = '\0'; // 将数据结束标志'\n'替换成字符串结束标志 if (flag_recv == USERNAME) { // 接收到的是用户名 name_num = find_name(recv_buf); switch (name_num) { case -1: send_data(conn_fd, "n\n"); break; case -2: exit(1); break; default: send_data(conn_fd, "y\n"); flag_recv = PASSWORD; break; } } else if (flag_recv == PASSWORD) { // 接收到的是密码 if (strcmp(users[name_num].password, recv_buf) == 0) { send_data(conn_fd, "y\n"); send_data(conn_fd, "Welcome login my tcp server\n"); printf("%s login\n", users[name_num].username); break; // 跳出while循环 } else send_data(conn_fd, "n\n"); } } close(sock_fd); close(conn_fd); exit(0); // 结束子进程 } else { // 父进程关闭刚刚接受的连接请求,执行accept等待其他连接请求 close(conn_fd); } } return 0; }