到目前爲止,小小項目大改了兩次。第一次實現了點對點的聊天,使用TCP套接字實現。第二次在第一次的基礎上實現了多線程處理聊天事件,通過線程同步實現。我把部分核心代碼貼出來,供大家交流。
總代碼量上千,全部貼出來不方便。客戶端和服務端都只分享主函數和線程函數。
server:
void recvandsend(void) //監聽轉發線程入口函數
{
int index = 0;
int nbytes = 0;
int reBytes = 0;
char mess_buff[2048];
message mess;
int len;
int outindex = 0;
char useName[32];
char useSerc[8];
printf("Servrer create receive socket and send message function succeed!\n");
while (1)
{
SOCKNODE *sock = &sockList;
while (sock->pNext != NULL) // 遍歷鏈表
{
sock = sock->pNext;
nbytes = 0;
memset(mess_buff, 0, sizeof(mess_buff));
nbytes = recv(sock->fd, mess_buff, sizeof(mess_buff), 0);
if (nbytes > 0) // 在某個套接字有消息進來
{
statusFlag = 0;
memcpy(&mess, mess_buff, sizeof(mess_buff));
switch(mess.sig_event)
{
case SIG_CLIENT_LOGON:
print_recv_mess(SIG_CLIENT_LOGON, mess.useName);
SOCKNODE *tr = &sockList;
while (tr->pNext != NULL)
{
tr = tr->pNext;
if (!strcmp(tr->person.useName, mess.useName) && !strcmp(tr->person.useSecr, mess.useSecr))
{
printf("%s logon succeed!\n", sock->person.useName);
send_client_mess(sock->fd, "Log on succeed!", SIG_CLIENT_LOGON_SUCCEED);
statusFlag = 1;
break;
}
}
if (statusFlag == 0)
{
fprintf(stderr, "This people is no exist, please resigter!\n");
send_client_mess(sock->fd, "Please Register!", SIG_CLIENT_REGISTER_ENABLE);
}
break;
case SIG_CLIENT_REGISTER:
print_recv_mess(SIG_CLIENT_REGISTER, mess.useName);
printf("client Name : %s\n", mess.useName);
printf("client Age : %s\n", mess.userAge);
printf("client Sex : %s\n", mess.userSex);
printf("client Phone: %s\n", mess.userPhone);
printf("client Secr : %s\n", mess.useSecr);
memcpy(sock->person.useName, mess.useName, strlen(mess.useName));
memcpy(sock->person.userAge, mess.userAge, strlen(mess.userAge));
memcpy(sock->person.userSex, mess.userSex, strlen(mess.userSex));
memcpy(sock->person.userPhone, mess.userPhone, strlen(mess.userPhone));
memcpy(sock->person.useSecr, mess.useSecr, strlen(mess.useSecr));
sock->person.status = 1;
send_client_mess(sock->fd, "Register Succeed, Please Login on!", SIG_CLIENT_REGISTER_SUCCEED);
break;
case SIG_TRASMIT_MESSAGE:
print_recv_mess(SIG_TRASMIT_MESSAGE, mess.useName);
send_client_mess(sock->fd, "Transmit message send succeed!", SIG_TRASMIT_MESSAGE_SUCCEED);
break;
case SIG_CLIENT_SEND_MSG:
print_recv_mess(SIG_CLIENT_SEND_MSG, sock->person.useName);
send_client_mess(sock->fd, "Chat message send succeed!", SIG_CLIENT_SEND_MSG_SUCCEED);
break;
case SIG_CLIENT_QUIT:
print_recv_mess(SIG_CLIENT_QUIT, sock->person.useName);
exitClient(sock);
send_client_mess(sock->fd, "LogOut succeed!", SIG_CLIENT_QUIT_SUCCEED);
break;
}
}
}
}
pthread_exit(NULL);
exit(1);
}
int main(int argc, char *argv[])
{
int sin_size;
int sockfd, new_fd;
int nbytes = 0;
int flags;
SOCKNODE *sockNew;
char buffer[1024];
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
pthread_t p_thread; /* thread's structure */
initList(&sockList); // 初始化套接字鏈表
if (argc != 1)
{
fprintf(stderr, "Usage:%sportnumber\a\n", argv[0]);
exit(1);
}
/* 服務器端開始建立 socket 描述符 */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf(stderr, "Socketerror:%s\n\a", strerror(errno));
exit(1);
}
/* 服務器端填充 sockaddr 結構 */
bzero(&server_addr, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(PORT);
/* 捆綁 sockfd 描述符 */
if (bind(sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr)) == -1)
{
fprintf(stderr, "Binderror:%s\n\a", strerror(errno));
exit(1);
}
printf("Server Port : %d ... ...\n", PORT);
/* 監聽 sockfd 描述符 */
if (listen(sockfd, LISTENQ) == -1)
{
fprintf(stderr, "Listenerror:%s\n\a", strerror(errno));
exit(1);
}
pthread_create(&p_thread, NULL, recvandsend, NULL);
while (1)
{
// 服務器阻塞,直到客戶程序建立連接
sin_size = sizeof(struct sockaddr_in);
new_fd = accept(sockfd, (struct sockaddr *)(&client_addr), &sin_size);
if (maxi >= MAXFD)
{
if ((new_fd != -1) && (closeConnection(new_fd) == 0))
{
close(new_fd);
printf("close %d connection success\n", new_fd);
}
}
else
{
if (new_fd == -1)
{
printf("socket Error!\n");
exit(1);
}
else
{
if (!connectSucceeddMess(new_fd))
{
insertList(&sockList, new_fd); // 新套接字插入到鏈表中
maxi = maxi + 1;
printf("add %d to list succeed!\n", new_fd);
}
}
}
}
close(sockfd);
exit(0);
}
client:
int main(int argc, char *argv[])
{
int running = 1;
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf(stderr, "create socket error : %s\n!", strerror(errno));
exit(1);
}
connect_server(); // 連接服務器
rec_mess_init(); // 初始化接收消息線程
while(threadFlag1){}; // 等待客戶端連接成功
client_worker_init(); // 客戶端工作線程初始化
while(threadFlag2){}; //
while(running)
{
if(!threadFlag2)
{
mutex_flag = 1; // 進入主工作線程
threadFlag2 = 1;
login_interface_init(0); //初始化界面
sleep(1);
}
}
}
/*接受消息線程初始化*/
void rec_mess_init()
{
pthread_t p_thread;
pthread_attr_t attr;
int iLoop = 5;
pthread_attr_init(&attr);
if(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
{
fprintf(stderr, "pthread_attr_setdetachstate failed!, Error Mess : [%s]", strerror(errno));
exit(1);
}
while(iLoop--)
{
if(pthread_create(&p_thread, &attr, recv_server_mess, NULL) == 0)
{
iLoop = 5;
printf("create receive thread succeed!\n");
break;
}
printf("recreate the receive message thread , %d ... ...\n", iLoop);
sleep(1);
}
if(iLoop != 5)
{
printf("create receive message thread failed!,Error Message : [%s]\n", strerror(errno));
exit(1);
}
pthread_attr_destroy(&attr);
}
// 初始化客戶端界面函數
// 主要處理客戶端註冊或者登錄事件
void client_worker_init()
{
int iLoop = 5;
pthread_t clientWorkerthread;
pthread_attr_t attr;
pthread_attr_init(&attr);
if(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
{
fprintf(stderr, "pthread_attr_setdetachstate failed!, Error Mess : [%s]", strerror(errno));
exit(1);
}
while(iLoop--)
{
if(pthread_create(&clientWorkerthread, &attr, client_worker_main, NULL) == 0)
{
iLoop = 5;
printf("client worker thread create succeed!\n");
break;
}
printf("recreate the receive message thread , %d ... ...\n", iLoop);
sleep(1);
}
if(iLoop != 5)
{
printf("create receive message thread failed!,Error Message : [%s]\n", strerror(errno));
exit(1);
}
pthread_attr_destroy(&attr);
}
歡迎大家交流,一起學習。