基于socket的Linux网络聊天程序--单线程非阻塞客户端
编译方式:
gcc -o chat_client chat_client.c
#include "chat.h"
#include <unistd.h> // for fork
#include <sys/signal.h> // for signal
#include <sys/wait.h> // for wait
#include <fcntl.h>
static char user_ID[BUFFER_SIZE]; //一个很大的缓冲区,实际ID_SIZE内有效
static char password[BUFFER_SIZE]; //一个很大的缓冲区,实际PASSWORD_SIZEE内有效
static int client_socket;
int connect_to_server(char * server_IP_addr)
{
//设置一个socket地址结构client_addr,代表客户机internet地址, 端口
struct sockaddr_in client_addr;
bzero(&client_addr,sizeof(client_addr)); //把一段内存区的内容全部设置为0
client_addr.sin_family = AF_INET; //internet协议族
client_addr.sin_addr.s_addr = htons(INADDR_ANY);//INADDR_ANY表示自动获取本机地址
client_addr.sin_port = htons(0); //0表示让系统自动分配一个空闲端口
//创建用于internet的流协议(TCP)socket,用client_socket代表客户机socket
client_socket = socket(AF_INET,SOCK_STREAM,0);
if( client_socket < 0)
{
printf("Create Socket Failed!\n");
return FAIL;
}
//把客户机的socket和客户机的socket地址结构联系起来
if( bind(client_socket,(struct sockaddr*)&client_addr,sizeof(client_addr)))
{
printf("Client Bind Port Failed!\n");
return FAIL;
}
//设置一个socket地址结构server_addr,代表服务器的internet地址, 端口
struct sockaddr_in server_addr;
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family = AF_INET;
if(inet_aton(server_IP_addr,&server_addr.sin_addr) == 0) //服务器的IP地址来自程序的参数
{
printf("Server IP Address Error!\n");
return FAIL;
}
server_addr.sin_port = htons(CHAT_SERVER_PORT);
socklen_t server_addr_length = sizeof(server_addr);
//向服务器发起连接,连接成功后client_socket代表了客户机和服务器的一个socket连接
if(connect(client_socket,(struct sockaddr*)&server_addr, server_addr_length) < 0)
{
printf("Can Not Connect To %s!\n",server_IP_addr);
return FAIL;
}
return SUCCEED;
}
void send_request_to_server(signed char request, char * option, char * to, char * message)
{
static chat_package buffer;
bzero((char*)&buffer,BUFFER_SIZE);
buffer.type = request;
memcpy(buffer.from, user_ID, ID_SIZE);
memcpy(buffer.password, password, PASSWORD_SIZE);
if(option)
memcpy(buffer.option, option, OPTION_SIZE);
if(to)
memcpy(buffer.to, to, ID_SIZE);
if(message)
memcpy(buffer.message, message, MESSAGE_SIZE);
if( send(client_socket,(char*)&buffer,BUFFER_SIZE,0)<0)
{
printf("Socket Send Data Failed Or Closed\n");
close(client_socket);
exit(0);
}
}
int receive_result_from_server(char * option, char * from, char * message)
{
chat_package buffer;
bzero((char*)&buffer,BUFFER_SIZE);
int length = recv(client_socket,(char*)&buffer,BUFFER_SIZE,0);
if(length<0)
{
printf("Receive Data From Server Failed\n");
}
if(option)
memcpy(option, buffer.option, OPTION_SIZE);
if(from)
memcpy(from, buffer.from, ID_SIZE);
if(message)
memcpy(message, buffer.message, MESSAGE_SIZE);
return buffer.type;
}
int receive_result_from_server_noblock(char * option, char * from, char * message)
{
chat_package buffer;
bzero((char*)&buffer,BUFFER_SIZE);
int flags = fcntl(client_socket, F_GETFL, 0);
fcntl(client_socket, F_SETFL, flags|O_NONBLOCK);
int length = recv(client_socket,(char*)&buffer,BUFFER_SIZE,0);
fcntl(client_socket, F_SETFL, flags);
if(option)
memcpy(option, buffer.option, OPTION_SIZE);
if(from)
memcpy(from, buffer.from, ID_SIZE);
if(message)
memcpy(message, buffer.message, MESSAGE_SIZE);
return buffer.type;
}
void print_user_list(char * user_list_buffer)
{
printf("\nUser_Online:\n");
char * user_id = user_list_buffer;
for( ; user_id<user_list_buffer+MESSAGE_SIZE; user_id+=ID_SIZE+1 )
printf("%s\t", user_id);
printf("\n");
}
void talk_to_server()
{
char message_buffer[BUFFER_SIZE]; ///一个很大的缓冲区,实际MESSAGE_SIZE内有效
bzero(message_buffer,BUFFER_SIZE);
char receiver_user_ID[BUFFER_SIZE]; ///一个很大的缓冲区,实际ID_SIZE内有效
bzero(receiver_user_ID,BUFFER_SIZE);
int command_option = NO_COMMAND;
while(command_option!=EXIT){
printf("Command Option:\n");
printf("%d:REGISTER\n",REGISTER);
printf("%d:LOGIN\n",LOGIN);
printf("%d:GET_USER_LIST\n",GET_USER_LIST);
printf("%d:TALK_TO\n",TALK_TO);
printf("%d:EXIT\n",EXIT);
printf("%d:GET_MESSAGE\n",GET_MESSAGE);
printf("Input Your Command Option Num: ");
scanf("%d",&command_option);
switch(command_option)
{
case REGISTER:
printf("Input Your User_ID:");
scanf("%s",user_ID);
printf("Input Your Password:");
scanf("%s",password);
send_request_to_server(command_option, 0, 0, 0);
break;
case LOGIN:
printf("Input Your User_ID:");
scanf("%s",user_ID);
printf("Input Your Password:");
scanf("%s",password);
send_request_to_server(command_option, 0, 0, 0);
break;
case GET_USER_LIST:
send_request_to_server(command_option, USER_LIST, 0, 0);
break;
case TALK_TO:
printf("Input Receiver User_ID:");
scanf("%s",receiver_user_ID);
printf("Write Your Message Here:");
scanf("%s", message_buffer);
send_request_to_server(command_option, 0, receiver_user_ID, message_buffer);
break;
case EXIT:
send_request_to_server(command_option, 0, 0, 0);
close(client_socket);
exit(0);
case CHANGE:
printf("Input Your New User_ID:");
scanf("%s",user_ID);
printf("Input Your New Password:");
scanf("%s",password);
send_request_to_server(command_option, 0, 0, 0);
case GET_MESSAGE:
break;
}
//recieve_from_server
char option[OPTION_SIZE+1]; bzero(option,OPTION_SIZE+1);
char message_from[ID_SIZE+1]; bzero(option,ID_SIZE+1);
char message[MESSAGE_SIZE+1]; bzero(message,MESSAGE_SIZE+1);
int response;
if(GET_MESSAGE==command_option)
response=receive_result_from_server_noblock(option, message_from, message);
else
response=receive_result_from_server(option, message_from, message);
switch(response)
{
case FAIL:
printf("\nRecived From Server: Failed\n");
break;
case SUCCEED:
if(strcmp(option, USER_LIST)==0)
print_user_list(message);
else
printf("\nRecieved From Server: OK\n");
break;
case TRANSFER:
printf("\nMessage From %s :%s\n",message_from, message);
break;
}
}
}
int main(int argc, char **argv)
{
if (argc != 2)
{
printf("Usage: ./%s ServerIPAddress\n",argv[0]);
exit(1);
}
bzero(user_ID,BUFFER_SIZE);
bzero(password,BUFFER_SIZE);
connect_to_server(argv[1]);
talk_to_server();
}