Linux區域網多人聊天軟體
功能介紹
- 客戶端:登陸及註冊;列出當前線上使用者列表、傳送聊天訊息、傳輸檔案等。
- 服務端:記錄註冊及線上使用者連結串列、記錄使用者聊天資料、顯示使用者的登陸退出等。
主要知識點:socket套接字、連結串列使用者管理、執行緒建立管理、IO複用、select監聽套接字、檔案讀寫等。
程式下載
服務端主函式程式碼:client.c
/*************************************************************************
> File Name: client.c
> Author: mrhjlong
> Mail: [email protected]
> Created Time: 2016年08月01日 星期一 14時40分39秒
************************************************************************/
#include "userlist.h"
void *func_ttl(void *arg)
{
int fd = (int)arg;
while(1)
{
cli_TTL(fd);
sleep(20);
}
return NULL;
}
int main(int argc, char *argv[])
{
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd < 0)
err_sys("socket error");
struct sockaddr_in des_addr;
des_addr.sin_family = AF_INET;
des_addr.sin_port = htons(9999);
inet_pton(AF_INET, "127.0.0.1", &des_addr.sin_addr);
//連線客戶端
int ret = connect(fd, (struct sockaddr *)&des_addr, sizeof(des_addr));
if(ret == -1)
err_sys("connect error");
//登陸和註冊登陸
ret = cli_REG_LOG(fd);
if(ret == -1) //放棄登陸或註冊,直接退出
{
close(fd);
return 0;
}
//建立執行緒傳送保活資訊
pthread_t pid;
ret = pthread_create(&pid, NULL, func_ttl, (void *)fd);
if(ret != 0)
err_sys("pthread create error");
MSG msgdata;
fd_set read_set;
int n;
int flag = 0;
char recv_buf[BUFSIZE] = {0};
char fname[50] = {0};
while(1)
{
FD_ZERO(&read_set);
if(flag == 0)
{
printf("Input a command: s-send | f-file | l-list | q-quit...\n");
FD_SET(0, &read_set);
}
FD_SET(fd, &read_set);
select(fd + 1, &read_set, NULL, NULL, NULL);
if(FD_ISSET(0, &read_set)) //輸入響應
{
bzero(&msgdata, sizeof(msgdata));
fgets(msgdata.cmd, 50, stdin);
if(strcmp(msgdata.cmd, "q\n") == 0) //退出
{
pthread_cancel(pid); //關閉執行緒
flag = 1;
shutdown(fd, SHUT_WR);
FD_CLR(0, &read_set);
continue;
}
else if(strcmp(msgdata.cmd, "l\n") == 0) //傳送命令,列出當前線上使用者
{
cli_LIST(fd);
continue;
}
else if(strcmp(msgdata.cmd, "s\n") == 0)
{
cli_SEND(fd, &msgdata);
}
else if(strcmp(msgdata.cmd, "f\n") == 0) //傳送FILE命令
{
bzero(fname, 50);
ret = cli_FILE(fd, &msgdata, fname);
if(ret == 0)
flag = 1;
continue;
}
else
{
printf("#################WARNING#################\n");
printf("Input error! Please try again!\n");
printf("#########################################\n");
continue;
}
}
if(FD_ISSET(fd, &read_set)) //接收資訊
{
bzero(recv_buf, BUFSIZE);
bzero(&msgdata, sizeof(msgdata));
n = recv(fd, recv_buf, BUFSIZE, 0);
if(n == 0) //關閉
{
printf("closed!\n");
break;
}
read_XML(recv_buf, &msgdata);
if(strcmp(msgdata.cmd, "LISTD") == 0)
{
printf("**************Online users:**************\n");
printf("%s\n", msgdata.text);
printf("*****************************************\n");
continue;
}
else if(strcmp(msgdata.cmd, "RECV") == 0)
{
printf("*****************RECV...*****************\n");
printf("FROM:%s\n", msgdata.name);
printf("MSG:%s\n", msgdata.text);
printf("*****************************************\n");
}
else if(strcmp(msgdata.cmd, "NOUSR") == 0)
{
printf("#################WARNING#################\n");
printf("User:%s is offline! Please try later.\n", msgdata.text);
printf("#########################################\n");
flag = 0;
}
else if(strcmp(msgdata.cmd, "LEAVE") == 0)
{
pthread_cancel(pid); //關閉執行緒
printf("cmd closed!\n");
break;
}
else if(strcmp(msgdata.cmd, "FCNT") == 0) //建立傳輸檔案連線,傳送
{
cli_FCNT(&msgdata, fname);
flag = 0;
}
else if(strcmp(msgdata.cmd, "FLSN") == 0) //建立傳輸檔案監聽, 接收資訊
{
cli_FLSN(fd, &msgdata);
}
}
}
close(fd);
return 0;
}
服務端主函式程式碼:server.c
/*************************************************************************
> File Name: server.c
> Author: mrhjlong
> Mail: [email protected]
> Created Time: 2016年08月01日 星期一 14時13分10秒
************************************************************************/
#include "userlist.h"
int main(void)
{
struct list_head list; //新建線上使用者連結串列
INIT_LIST_HEAD(&list); //初始化連結串列頭
struct list_head usrList; //新建已註冊使用者連結串列
INIT_LIST_HEAD(&usrList);
FILE *fp = fopen("regUser.txt", "r");
if(fp == NULL)
err_sys("open regUser.txt error!\n");
//獲取已註冊使用者連結串列
get_user_list(fp, &usrList);
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
err_sys("socket error");
int optval = 1;
int ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int));
if(ret == -1)
err_sys("setsockopt error!");
//伺服器地址埠設定
struct sockaddr_in my_addr;
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(9999);
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//繫結伺服器
ret = bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr));
if(ret != 0)
err_sys("bind error");
//監聽
ret = listen(sockfd, 10);
if(ret != 0)
err_sys("listen error");
printf("listening...\n");
fd_set read_set;
MSG msgdata;
char recv_buf[BUFSIZE] = {0};
int n;
struData_t *p = NULL;
struct list_head *pos = NULL;
struct timeval timeout;
LD ldata;
while(1)
{
FD_ZERO(&read_set);
FD_SET(sockfd, &read_set);
FD_SET(0, &read_set);
//遍歷連結串列,新增套接字到select
list_for_each(pos, &list)
{
p = list_entry(pos, struData_t, list);
FD_SET(p->sockfd, &read_set);
}
//設定select
timeout.tv_sec = 3; //阻塞3秒
timeout.tv_usec = 0;
if(pos->prev == &list)
ret = select(sockfd + 1, &read_set, NULL, NULL, &timeout);
else
{
p = list_entry(pos->prev, struData_t, list);
ret = select(p->sockfd + 1, &read_set, NULL, NULL, &timeout);
}
//超時返回,檢測客戶保活資訊
if(ret == 0)
{
chk_ttl(&list);
continue;
}
//服務端退出
if(FD_ISSET(0, &read_set))
{
char cmd_quit[50] = {0};
fgets(cmd_quit, 50, stdin);
if(strcmp(cmd_quit, "q\n") == 0) //輸入q退出
{
ser_quit(&usrList, &list);
printf("Closing server!\n");
break;
}
else if(strcmp(cmd_quit, "s\n") == 0) //輸入s顯示聊天記錄
{
FILE *fp = fopen("Chatlog.txt", "r");
char buffer[100] = {0};
if(fp == NULL)
printf("open Chatlog.txt error!\n");
printf("*****************Chat record:******************\n");
fgets(buffer, 100, fp);
while(strlen(buffer) >= 8)
{
printf("%s", buffer);
bzero(buffer, 100);
fgets(buffer, 100, fp);
}
printf("***********************************************\n");
}
else if(strcmp(cmd_quit, "l\n") == 0) //輸入l獲取已註冊使用者資訊
{
FILE *fp = fopen("regUser.txt", "r");
if(fp == NULL)
err_sys("open regUser.txt error!\n");
//獲取已註冊使用者連結串列
get_user_list(fp, &usrList);
}
else
printf("Input error! Please try again!\n");
continue;
}
//監聽套接字響應
if(FD_ISSET(sockfd, &read_set))
{
ldata.sockfd = sockfd;
ldata.usrList = &usrList;
ldata.list = &list;
//建立處理註冊和登陸操作的執行緒
pthread_t pid;
int n = pthread_create(&pid, NULL, listen_reg_log, (void *)&ldata);
if(n != 0)
err_sys("pthread create error");
n = pthread_detach(pid);
if(n != 0)
err_sys("pthread detach error");
usleep(200); //等待執行緒accept,否則會重複建立執行緒
ret--;
}
//客戶端套接字響應,接收到資訊
if(ret > 0)
{
//遍歷連結串列,找到響應的套接字
list_for_each(pos, &list)
{
p = list_entry(pos, struData_t, list);
if(FD_ISSET(p->sockfd, &read_set))
break;
}
bzero(recv_buf, BUFSIZE);
n = recv(p->sockfd, recv_buf, BUFSIZE, 0);
//客戶端主動關閉,服務端釋放記憶體
if(n == 0)
{
printf("User:%s is leaving...\n", p->client_name);
close(p->sockfd);
list_del(pos);
free(p);
continue;
}
bzero(&msgdata, sizeof(msgdata));
read_XML(recv_buf, &msgdata); //解析XML資料
if(strcmp(msgdata.cmd, "LIST") == 0) //LIST命令處理
{
ser_LIST(p->sockfd, &list, &msgdata);
continue;
}
else if(strcmp(msgdata.cmd, "TTL") == 0) //TTL命令處理
{
time(&(p->ttl)); //重置保活時間
continue;
}
else if(strcmp(msgdata.cmd, "SEND") == 0) //SEND命令處理
{
ser_SEND(p->sockfd, p->client_name, &list, &msgdata);
continue;
}
else if(strcmp(msgdata.cmd, "FILE") == 0)
{
ser_FILE(p->sockfd, p->client_name, &list, &msgdata);
}
}
}
close(sockfd);
return 0;
}
相關推薦
Linux區域網多人聊天軟體
功能介紹 客戶端:登陸及註冊;列出當前線上使用者列表、傳送聊天訊息、傳輸檔案等。 服務端:記錄註冊及線上使用者連結串列、記錄使用者聊天資料、顯示使用者的登陸退出等。 主要知識點:socket套接字、連結串列使用者管理、執行緒建立管理、IO複用、selec
Linux下基於Socket網絡通信的多人聊天室
data break arp pre font linu print lose types.h 服務端 #include <stdio.h> #include <sys/types.h> #include <sys/socket.h>
linux c++select多人聊天程式
比較簡單的多人聊天程式,可直接執行。 主要是實現功能。沒有介面也沒有多餘功能,只是實現群聊天的功能。c/s模式。 server端用select多路複用來做,可以接受多個客戶端連線。client端啟動2個執行緒控制傳送和接受資料。 ======================
linux c 基於UDP的多人聊天程式
client.c #include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> #include<sys/types.h> #
linux環境下的多人聊天程式設計
STEP 1:老師給出了原始的程式,是功能不完善的,也就是讓我們把發信息的使用者名稱和時間啥的顯示出來,這樣不是比較合理嘛;原程式是可以實現傳text的,就是沒有使用者名稱而已。 先跑一下(切換到你放這三檔案的目錄哦~):gcc -o chat chat.c 回車 然後:.
Node + H5 + WebSocket + Koa2 實現簡單的多人聊天
接收 var msg ont for document back next bsp 服務器代碼 ( 依賴於 koa2, koa-websocket ) /* 實例化外部依賴 */ let Koa = require("koa2"); let WebSocket = r
NIO 多人聊天室
fig pin 仿真 all listen HR code cas ole 一前言 在家休息沒事,敲敲代碼,用NIO寫個簡易的仿真聊天室。下面直接講聊天室設計和編碼。對NIO不了解的朋友,推薦一個博客,裏面寫的很棒: https://javadoop.com/ 裏面
h5移動端聊天室|仿微信界面聊天室|h5多人聊天室
dde ... html5開發 技術 show scrollby anim 世界 info 今年的FIFA世界杯甚是精彩,最近興致高漲就利用HTML5開發了一個手機端仿微信界面聊天室,該h5聊天室采用750px全新伸縮flex布局,以及使用rem響應式配合fontsize
基於tcp和多線程的多人聊天室-C語言
同時 reat 錯誤 con play 分享圖片 tdi %s 線程編程 之前在學習關於網絡tcp和多線程的編程,學了知識以後不用一下總絕對心虛,於是就編寫了一個基於tcp和多線程的多人聊天室。 具體的實現過程: 服務器端:綁定socket對象->設置監聽數-
【WebSocket】---多人聊天系統
tom after channel 加載 cal parse ssi 獲得 路徑 多人聊天系統 功能說明:多人聊天系統,主要功能點: 1、當你登陸成功後,可以看到所有在線用戶(實際開發可以通過redis實現,我這邊僅僅用map集合) 2、實現群聊功能,
nio 代碼實現簡易多人聊天
false size spl closed write content 輸入 utf oom 這幾天在學習nio相關知識。實現了一個簡單的多人聊天程序。 服務端代碼; 1 import java.io.IOException; 2 import java.net
【181027】VC++簡單多人聊天室原始碼
一個簡單的但支援多人同時聊天的VC++聊天室原始碼,支援私聊、支援真實IP相互傳送檔案,使用者名稱可以重複,當用戶進入聊天室時其它使用者會得到通知,伺服器端採用埠模型完成,客戶端採用WSAAynscSelect模型,底層採用xml對傳輸協議進行封裝。伺服器啟動後自動監聽客戶端是否執行,聊天過程中
1024_(即時通訊)使用node.js和socket.io實現多人聊天室
使用node.js和socket.io實現多人聊天室 2015年01月24日 03:24:54 遠古大猛獁 閱讀數:2775 轉自: http://www.cnblogs.com/flyoung2008/archive/2012/07/19/2600132.html
Netty多人聊天室
在簡單聊天室的程式碼中修改ChatServerHandler類,就可以模擬多人聊天的功能 package com.cppdy.server; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext;
Java通過Socket來實現簡單多人聊天室
Socket可以實現網路上兩個程式通過雙向通道進行資料的交換,此外它是Java中網路TCP/IP協議的封裝,例如可以進行網路通訊等等,下面我們就來簡單寫一下多人聊天室。 首先來分析一下要實現的流程 首先建立一個伺服器端,構建ServerSocket並繫結埠 建立sock
Python網路程式設計----實現簡單的多人聊天室
還是用UDP,socket作為主體來實現,之前我們已經實現過單對單socket通訊,這次想實現群發功能 原理其實就是一臺伺服器在負責分配轉發資料,來達成廣播的效果,這些思路其實也差不多 但是多人聊天沒有這麼強的規整性,你可能沒等到A的訊息,就要去和B說話了,多執行緒就可以
基於flask框架,使用websocket實現多人聊天室功能
後端程式碼: # web_socket 的收發機制 # web_socket --> web + socket --> http協議 + socket # web_socket協議就是ws協議 # 基於flask框架為web_socket提供服務 from flas
Go語言專案實戰:多人聊天室
功能需求 實現單撩 實現群撩 實現使用者上線的全網通知 實現使用者暱稱 實現聊天日誌的儲存和檢視 服務端實現 type Client struct { conn net.Conn name string addr string } var ( //
使用netty實現一個多人聊天室--failed: Error during WebSocket handshake: Unexpected response code: 200
初次接觸netty , 本文主要內容如下: 遇到的小bug 聊天室後端程式碼: 聊天室前端程式碼: 遇到的小bug 在使用netty進行websocket程式設計(實現一個簡單的聊天室)時,我遇到了這樣一個奇怪
JAVA_網路程式設計_TCP_Socket通訊_聊天室_多人聊天/私聊_實現
Socket程式設計 連線(連線是通過輸入輸出流來傳送資料) 建立伺服器 package com.hp.tcp; import java.io.DataInputStream; import java.io.DataOutputStream; import