史啦啦 的學生作業:
#include
#include
#include
#include
#include /* See NOTES */
#include
#include
#include
#include
#include
#include
#define LOGIN_SUCCESS 1
#define LOGIN_FAILURE 0
typedef struct
{
char *ip;
unsigned char flag;
struct sockaddr_in *peer_addr;
}thread_type;
void printf_client_info(struct sockaddr_in *addr,char *buf)
{
printf("===============================\n");
printf("user IP : %s\n",inet_ntoa(addr->sin_addr));
printf("user port : %d\n", ntohs(addr->sin_port));
printf("user data : %s\n",buf);
}
//1.初始化socket連接
int init_socket(const char *ip,const char *port)
{
int sockfd = 0;
struct sockaddr_in my_addr;
socklen_t len = sizeof(my_addr);
//1.通過socket創建文件描述符
sockfd = socket(AF_INET,SOCK_DGRAM ,0);
if(sockfd < 0)
{
perror("Fail to socket!");
exit(EXIT_FAILURE);
}
//2.填充服務器自己的ip地址和port,然后綁定
memset(&my_addr,0,sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(atoi(port));
my_addr.sin_addr.s_addr = inet_addr(ip);
if(bind(sockfd,(struct sockaddr *)&my_addr,len) < 0)
{
perror("Fail to bind");
return -1;
}
return sockfd;
}
void recv_data(int new_sockfd)
{
int n = 0;
char buf[1024] = {0};
struct sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
//3.發送數據
while(1)
{
memset(buf,0,sizeof(buf));
n = recvfrom(new_sockfd,buf,sizeof(buf),0,(struct sockaddr *)&client_addr,&len);
if(n < 0)
{
perror("Fail to recvfrom");
exit(EXIT_FAILURE);
}
printf_client_info(&client_addr,buf);
if(strncmp(buf,"quit",4) == 0)
break;
}
close(new_sockfd);
return ;
}
void *message_thread(void *arg)
{
thread_type *packet = (thread_type *)arg;
//1.給用戶回復的秘鑰正確信息
char *ip = packet->ip;
unsigned char login_flag = packet->flag;
struct sockaddr_in *addr = packet->peer_addr;
//創建套接字,獲得用戶數據,綁定0號端口,系統會隨機分配一個可用的端口
int new_sockfd = init_socket(ip,"0");
sendto(new_sockfd,&login_flag,sizeof(login_flag),0,(struct sockaddr *)addr,sizeof(struct sockaddr_in));
//接收數據
recv_data(new_sockfd);
pthread_exit(NULL);
}
void user_login(const char *ip,const char *port)
{
int n = 0;
char buf[1024] = {0};
struct sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
unsigned char login_flag;
int sockfd;
thread_type packet;
pthread_t tid;
//1.創建套接字,獲得用戶數據
sockfd = init_socket(ip,port);
//2.接收登錄數據
while(1)
{
memset(buf,0,sizeof(buf));
n = recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&client_addr,&len);
if(n < 0)
{
perror("Fail to recvfrom");
exit(EXIT_FAILURE);
}
printf("key = %s\n",buf);
login_flag = (strncmp(buf,"root",4) == 0) ? LOGIN_SUCCESS : LOGIN_FAILURE;
//說明此時秘鑰正確
if(login_flag == LOGIN_SUCCESS)
{
packet.ip = (char *)ip;
packet.flag = login_flag;
packet.peer_addr = &client_addr;
//創建子線程,子線程準備接收當前用戶數據,主線程接續接收新用戶的秘鑰
pthread_create(&tid,NULL,message_thread,(void *)&packet);
}else{
//秘鑰不正確,使用原始端口回復信息
sendto(sockfd,&login_flag,sizeof(login_flag),0,(struct sockaddr *)&client_addr,len);
}
//把線程設置為分離式,子線程結束后,系統會自動回收資源
pthread_detach(tid);
}
return ;
}
//./a.out ip port
int main(int argc, const char *argv[])
{
int sockfd;
unsigned char login_flag;
if(argc < 3)
{
fprintf(stderr,"Usage : %s ip port!\n",argv[0]);
exit(EXIT_FAILURE);
}
//1.接收用戶的秘鑰,準備登錄
user_login(argv[1],argv[2]);
return 0;
}