【tcp-ip學習總結】基於udp的多人聊天室,帶有登入註冊功能
環境;vs2010,vs2013
伺服器端
#include<stdio.h>
#include<Winsock2.h>
#include<stdlib.h>
#pragma comment(lib,"Ws2_32.lib")
typedef struct {
char username[30];//使用者名稱
char password[50];//使用者密碼
struct sockaddr_in addr;//使用者的地址
int isOnlie;//是否線上
}User;
SOCKET severSocket;//服務端的socket
WSADATA wsaData;
struct sockaddr_in serverAddr, clientAddr, showMsgAddr;//伺服器端地址,客戶端地址,客戶端那邊訊息顯示框的地址
char recvBuf[1024];//接收緩衝區
struct sockaddr_in addrs[10];//客戶端地址陣列(裝有每一個客戶端的地址)
int count = 0;//地址陣列中元素的個數
int clientaddrLen;//伺服器端的地址長度
int recvlen;//接收字串的長度
int i = 0;//迴圈需要的變數
int res;//字串比較的結果
int sendLen;//傳送資料的長度
char clientIP[1024];//儲存當前客戶端地址
char addrIP[1024];//儲存陣列中第i個客戶端的地址
char command;//使用者輸入的命令
User users[100];
int userCount;//使用者的數量
char sendBuf[1024];//傳送給客戶端的提示字串
char username[30];//登陸人的名字
char password[50];//登陸人的密碼
char *delimiters;//分割的字串
int onlineCount;//顯示線上人數
char onlineStr[100];//線上人數的字串格式
/*登陸功能*/
void login(){
printf("登陸!\n" );
//如果接收的整個字串為a,就提示登陸方法,否則就執行登陸
if (!strcmp("a", recvBuf)) {
strcpy(sendBuf, "登陸請在傳送框輸入(a 使用者名稱 密碼)按回車\n");
sendLen = sendto(severSocket, sendBuf, sizeof(sendBuf), 0, (SOCKADDR*)&showMsgAddr, sizeof(showMsgAddr));
if (sendLen == SOCKET_ERROR) {
printf("傳送失敗!");
return;
}
}
else {
//分割字串
delimiters = strtok(recvBuf, " ");
delimiters = strtok(NULL, " ");
strcpy(username, delimiters);//拿到登陸的username
delimiters = strtok(NULL, " ");
strcpy(password, delimiters);//拿到登陸的密碼
for (i = 0; i < userCount; i++) {
if (!strcmp(username, users[i].username)){
if (!strcmp(password, users[i].password)) {
if (users[i].isOnlie == 1) {//判斷是否重複登陸
strcpy(sendBuf, "不好意思您重複登陸了!\n");
sendLen = sendto(severSocket, sendBuf, sizeof(sendBuf), 0, (SOCKADDR*)&showMsgAddr, sizeof(showMsgAddr));
return;
}
else {
users[i].isOnlie = 1;
onlineCount++;
users[i].addr = showMsgAddr;
printf("一個客戶登陸,客戶的ip為:%s----埠號為%d\n", inet_ntoa(showMsgAddr.sin_addr), ntohs(showMsgAddr.sin_port));
sprintf(onlineStr, "%d", onlineCount);//吧int型別的數轉為字串
strcpy(sendBuf, "客戶登陸,目前線上人數為 ");
strcat(sendBuf, onlineStr);
strcat(sendBuf, "\n");
//傳送給所有的客戶端
for (i = 0; i < userCount; i++) {
if (users[i].isOnlie == 1) {
sendLen = sendto(severSocket, sendBuf, sizeof(sendBuf), 0, (SOCKADDR*)&users[i].addr, sizeof(users[i].addr));
if (sendLen == SOCKET_ERROR) {
printf("傳送失敗!");
return;
}
}
}
return;
}
}
else {
strcpy(sendBuf, "密碼錯誤\n");
sendLen = sendto(severSocket, sendBuf, sizeof(sendBuf), 0, (SOCKADDR*)&showMsgAddr, sizeof(showMsgAddr));
return;
}
}
}
strcpy(sendBuf, "不存在此使用者名稱,請註冊\n");
sendLen = sendto(severSocket, sendBuf, sizeof(sendBuf), 0, (SOCKADDR*)&showMsgAddr, sizeof(showMsgAddr));
return;
}
}
/*註冊功能*/
void logout() {
printf("註冊\n");
printf("一個客戶正在註冊,客戶的ip為:%s----埠號為%d\n", inet_ntoa(showMsgAddr.sin_addr), ntohs(showMsgAddr.sin_port));
if (!strcmp("b", recvBuf)) {
strcpy(sendBuf, "註冊請在傳送框輸入(b 使用者名稱 密碼)按回車\n");
sendLen = sendto(severSocket, sendBuf, sizeof(sendBuf), 0, (SOCKADDR*)&showMsgAddr, sizeof(showMsgAddr));
if (sendLen == SOCKET_ERROR) {
printf("傳送失敗!");
return;
}
}
else {
//分割字串
delimiters = strtok(recvBuf, " ");
delimiters = strtok(NULL, " ");
strcpy(username, delimiters);//拿到註冊的username
delimiters = strtok(NULL, " ");
strcpy(password, delimiters);//拿到註冊的密碼
/*判斷是不是已經存在使用者名稱*/
for (i = 0; i < userCount; i++) {
if(!strcmp(username, users[i].username) ){
strcpy(sendBuf, "使用者名稱已經存在!\n");
sendLen = sendto(severSocket, sendBuf, sizeof(sendBuf), 0, (SOCKADDR*)&showMsgAddr, sizeof(showMsgAddr));
if (sendLen == SOCKET_ERROR) {
printf("傳送失敗!");
return;
}
}
}
//如果沒有存在就給結構體賦值
strcpy(users[i].username, username);
strcpy(users[i].password, password);
users[i].addr = showMsgAddr;
userCount++;
strcpy(sendBuf, "註冊成功,請登陸\n");
sendLen = sendto(severSocket, sendBuf, sizeof(sendBuf), 0, (SOCKADDR*)&showMsgAddr, sizeof(showMsgAddr));
if (sendLen == SOCKET_ERROR) {
printf("傳送失敗!");
return;
}
}
}
/*登出登陸*/
void LogOff() {
/*判斷髮出注銷功能的是哪一個使用者*/
strcpy_s(clientIP, 1024, inet_ntoa(showMsgAddr.sin_addr));
for (i = 0; i < userCount; i++) {
strcpy_s(addrIP, 1024, inet_ntoa(users[i].addr.sin_addr));
if (!strcmp(clientIP, addrIP)) {
users[i].isOnlie = 0;
strcpy(sendBuf, "成功退出! ");
sendLen = sendto(severSocket, sendBuf, sizeof(sendBuf), 0, (SOCKADDR*)&showMsgAddr, sizeof(showMsgAddr));
}
}
onlineCount--;//線上人數-1
sprintf(onlineStr, "%d", onlineCount);
strcpy(sendBuf, "有一個使用者退出,目前線上人數為 ");
strcat(sendBuf, onlineStr);
strcat(sendBuf, "\n");
for (i = 0; i < userCount; i++) {
if (users[i].isOnlie == 1) {
sendLen = sendto(severSocket, sendBuf, sizeof(sendBuf), 0, (SOCKADDR*)&users[i].addr, sizeof(users[i].addr));
if (sendLen == SOCKET_ERROR) {
printf("傳送失敗!");
return;
}
}
}
}
/*群聊功能*/
void groupChar() {
//printf("群聊\n");
if (!strcmp("c", recvBuf)) {
strcpy(sendBuf, "請暢所欲言吧!\n");
sendLen = sendto(severSocket, sendBuf, sizeof(sendBuf), 0, (SOCKADDR*)&showMsgAddr, sizeof(showMsgAddr));
if (sendLen == SOCKET_ERROR) {
printf("傳送失敗!");
return;
}
}
else {
strcpy_s(clientIP, 1024, inet_ntoa(showMsgAddr.sin_addr));
for (i = 0; i < userCount; i++) {
strcpy_s(addrIP, 1024, inet_ntoa(users[i].addr.sin_addr));
if (!strcmp(clientIP, addrIP)) {
strcpy(username, users[i].username);
}
}
strcat(username, " : ");
strcat(username, recvBuf);
strcpy(recvBuf, username);
//取出users裡面的每一個使用者
for (i = 0; i < userCount; i++) {
if (users[i].isOnlie == 1) {
sendLen = sendto(severSocket, recvBuf, sizeof(recvBuf), 0, (SOCKADDR*)&users[i].addr, sizeof(users[i].addr));
if (sendLen == SOCKET_ERROR) {
printf("傳送失敗!");
return;
}
}
}
}
}
/*私聊功能*/
void privateChat() {
printf("私聊\n");
}
void main() {
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
printf("協議棧載入失敗!");
return;
}
//建立socket
severSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (severSocket == INVALID_SOCKET) {
printf("套介面建立失敗!");
return;
}
//初始化地址
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(8888);
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
//繫結套介面
if (bind(severSocket, (LPSOCKADDR)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
printf("套介面繫結失敗!");
return;
}
clientaddrLen = sizeof(clientAddr);
memset(recvBuf, 0, sizeof(recvBuf));
printf("-------------伺服器在等待-------------\n");
//開始接收資料
while (1) {
recvlen = recvfrom(severSocket, recvBuf, 1024, 0, (SOCKADDR*)&clientAddr, &clientaddrLen);
showMsgAddr = clientAddr;
showMsgAddr.sin_port = ntohs(6666);//把埠地址改為6666
if (recvlen != 0) {
if (recvBuf[0] == 'a') {
login();
}
else if (recvBuf[0] == 'b') {
logout();
}
else if(!strcmp(recvBuf, "end")){
LogOff();
}
else {
groupChar();
}
}
}
closesocket(severSocket);
WSACleanup();
}
客戶端
#include<stdio.h>
#include<Winsock2.h>
#include<stdlib.h>
#pragma comment(lib,"Ws2_32.lib")
SOCKET clientSocket;
WSADATA wsaData;
char sendBuf[1024];
struct sockaddr_in serverAddr;
int sendLen;//傳送資料的長度
void main() {
//載入協議棧
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
printf("協議棧載入失敗!");
return;
}
//建立客戶端的socket
clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (clientSocket == INVALID_SOCKET) {
printf("套介面建立失敗!");
return;
}
//初始化目標伺服器的地址
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(8888);
serverAddr.sin_addr.s_addr = inet_addr("172.18.130.230");
while (1) {
printf("輸入要傳送的資料:");
gets_s(sendBuf, 1024);
sendLen = sendto(clientSocket, sendBuf,sizeof(sendBuf), 0, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
if (sendLen == SOCKET_ERROR) {
printf("傳送失敗!");
return;
}
}
}
客戶端顯示訊息端
#include<stdio.h>
#include<Winsock2.h>
#include<stdlib.h>
#pragma comment(lib,"Ws2_32.lib")
SOCKET severSocket;
WSADATA wsaData;
struct sockaddr_in serverAddr, clientAddr;
char recvBuf[1024];
int recvlen;//接收資料的長度
int clientaddrLen;//客戶端地址長度
void showUI() {
printf("------------------------------------------------------------------\n");
printf("-----------------------歡迎來到狒狒聊天室-------------------------\n");
printf("------------------------請輸入下列字母----------------------------\n");
printf("------------a:登陸 b:註冊 c:群聊 d:私聊 end:退出登陸--------\n");
printf("------------------------------------------------------------------\n");
}
void main() {
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
printf("協議棧載入失敗!");
return;
}
//建立socket
severSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (severSocket == INVALID_SOCKET) {
printf("套介面建立失敗!");
return;
}
//初始化地址
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(6666);
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
//繫結套介面
if (bind(severSocket, (LPSOCKADDR)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
printf("套介面繫結失敗!");
return;
}
clientaddrLen = sizeof(clientAddr);
memset(recvBuf, 0, sizeof(recvBuf));
showUI();//呼叫顯示介面函式
//開始接收資料
while (1) {
recvlen = recvfrom(severSocket, recvBuf, 1024, 0, (SOCKADDR*)&clientAddr, &clientaddrLen);
if (recvlen != 0) {
printf("%s\n", recvBuf);
//printf("客戶的ip為:%s----埠號為%d", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
//傳送給客戶
//int sendLen = sendto(severSocket, recvBuf, sizeof(recvBuf), 0, (SOCKADDR*)&clientAddr, clientaddrLen);
//if (sendLen == SOCKET_ERROR) {
// printf("傳送失敗!");
// break;
//}
}
}
closesocket(severSocket);
WSACleanup();
}
相關推薦
【tcp-ip學習總結】基於udp的多人聊天室,帶有登入註冊功能
環境;vs2010,vs2013 伺服器端 #include<stdio.h> #include<Winsock2.h> #include<stdlib.h> #pragma comment(lib,"Ws2_32
【tcp-ip學習總結】使用tcp協議實現簡單的通訊小程式
環境:vs2013 server.c #include<Winsock2.h> #include<stdio.h> #pragma comment(lib,"Ws2_32.lib") #include<stdlib.h&
【181027】VC++簡單多人聊天室原始碼
一個簡單的但支援多人同時聊天的VC++聊天室原始碼,支援私聊、支援真實IP相互傳送檔案,使用者名稱可以重複,當用戶進入聊天室時其它使用者會得到通知,伺服器端採用埠模型完成,客戶端採用WSAAynscSelect模型,底層採用xml對傳輸協議進行封裝。伺服器啟動後自動監聽客戶端是否執行,聊天過程中
【TCP/IP網路程式設計】:06基於UDP的伺服器端/客戶端
本篇文章簡單描述了UDP傳輸協議的工作原理及特點。 理解UDP UDP和TCP一樣同屬於TCP/IP協議棧的第二層,即傳輸層。 UDP套接字的特點 UDP的工作方式類似於傳統的信件郵寄過程。寄信前應先在信封上填好寄信人和收信人的地址,之後貼上郵票放進郵筒即可。當然信件郵寄過程可能會發生丟失,我們也無法隨時知曉
【Spark深入學習 -10】基於spark構建企業級流處理系統
變現 大內存 空間換時間 detail python 訪問量 新版本 kafak 計算框架 ----本節內容------- 1.流式處理系統背景 1.1 技術背景 1.2 Spark技術很火 2.流式處理技術介紹 2.1流式處理技術概念 2.
【Python爬蟲學習實踐】基於Beautiful Soup的網站解析及數據可視化
為我 enc lambda ech 和我 find weather acc 節點 在上一次的學習實踐中,我們以Tencent職位信息網站為例,介紹了在爬蟲中如何分析待解析的網站結構,同時也說明了利用Xpath和lxml解析網站的一般化流程。在本節的實踐中,我們將以中國天氣網
【Java TCP/IP Socket程式設計】----進階----多工處理
簡介 基本的TCP相應伺服器是一次只能處理一個客戶端請求,無法處理同時多個客戶端請求,Java中多執行緒技術解決這一問題。多執行緒有兩種方式:一是一客戶一執行緒;二是執行緒池; 1)一客戶一執行緒:即為每個連線建立一個執行緒來處理,伺服器端會迴圈執行,監聽指定埠的連線,反覆接收來
【Spring Boot學習總結】14.Spring Boot整合Redis-與傳統方式對比
前面我們講解了如何使用Spring Boot來控制事務,下面我們來講解一下如何使用Spring Boot來整合Redis 為了對比傳統工程與Spring Boot整合的不同,以及彰顯Spring Boot整合的優勢,我們會逐一剖析傳統整合方式與Spring Boot整合方式。 一、傳統方式整
【Spring Boot學習總結】13.Spring Boot事務控制
上一篇我們講解了Spring Boot與MyBatis的結合開發,併成功操作了資料庫。眾所周知,保證資料庫一致性的操作,就是事務的控制。 而Spring事務管理可以分為兩種:程式設計式以及宣告式。 其中程式設計式事務就是使用編寫程式碼的方式,進行事務的控制。而宣告式事務一般通
TCP/IP學習總結整理
TCP/IP的基本總結: 1.TCP/IP是一個協議簇,是一個開放的協議標準,所有人都可以免費使用,並且是獨立於硬體和作業系統的。 2.TCP/IP協議是不區分網路硬體的,它在區域網,廣域網和網際網路中都被廣泛使用。 3.TCP/IP協議使用統一的網路地址分配的方案,網
【51微控制器學習筆記】基於STC89C52製作的交通訊號燈
一、簡介 近來學(玩)了下已經好久沒碰的51,心血來潮自己DIY了一個交通訊號燈模型。沒有什麼創新之處,就是復(dao)習(gu)復(dao)習(gu)了下51的定時器中斷、外部中斷以及最小系統電路,熟悉了下74HC595的用法和數碼管。因為好久沒碰51了導致數
【Spring Boot學習總結】6.SpringBoot全域性配置檔案
上一篇我們總結了SpringBoot的核心註解以及一些簡單的配置,本篇我們來了解SpringBoot的全域性配置檔案。 Spring Boot專案使用一個全域性配置檔案application.properties或者是application.yml,在resource目錄下
【TCP/IP網路程式設計】:09套接字的多種可選項
本篇文章主要介紹了套接字的幾個常用配置選項,包括SO_SNDBUF & SO_RCVBUF、SO_REUSEADDR及TCP_NODELAY等。 套接字可選項和I/O緩衝大小 前文關於套接字的描述僅僅是使用其預設套接字特性來進行資料通訊,這對於簡單的使用場景來說似乎是可以的,然而實際工作場景中的確需要
基於tcp和多線程的多人聊天室-C語言
同時 reat 錯誤 con play 分享圖片 tdi %s 線程編程 之前在學習關於網絡tcp和多線程的編程,學了知識以後不用一下總絕對心虛,於是就編寫了一個基於tcp和多線程的多人聊天室。 具體的實現過程: 服務器端:綁定socket對象->設置監聽數-
15.基於UDP協議的聊天室程式
使用UDP協議完成一個聊天室程式的小專案,大部分程式碼都有註釋,一看就能看到的. 實現的功能: (1)檢視/顯示已經登陸的使用者資訊 (2)向已登陸的使用者傳送訊息 (3)輸出錯誤訊息,給
c++網路通訊多人聊天室Server端執行程式碼,及小白的學習情況和經驗總結
c++網路通訊多人聊天室Server端 一、描述 1> 採用c++語言 2>編譯環境是vs2015 3>使用的是阻塞式套接字 二、功能描述 1>一個伺服器對多個客戶端 2>通過廣播的方式使得客戶端與伺服器端都能夠接收到彼此的訊息 3>伺
pyqt5 基於UDP的簡單聊天室
UDP通訊過程:建立QUdpSocket,之後將socket繫結到對應的埠號,在接受文字時,socket函式會觸發readyRead訊號,在對應的槽函式中編寫處理資料處理的過程,讀取資料使用readDatagram函式。# def readDatagram(self, p_i
Linux下基於Socket網絡通信的多人聊天室
data break arp pre font linu print lose types.h 服務端 #include <stdio.h> #include <sys/types.h> #include <sys/socket.h>
基於flask框架,使用websocket實現多人聊天室功能
後端程式碼: # web_socket 的收發機制 # web_socket --> web + socket --> http協議 + socket # web_socket協議就是ws協議 # 基於flask框架為web_socket提供服務 from flas
Python基於Socket實現簡易多人聊天室
##前言 套接字(Sockets)是雙向通訊通道的端點。 套接字可以在一個程序內,在同一機器上的程序之間,或者在不同主機的程序之間進行通訊,主機可以是任何一臺有連線網際網路的機器。 套接字可以通過多種不同的通道型別實現:Unix域套接字,TCP,UDP等。 套接字型檔提供了處理公共傳輸的特定類,以及一個用於處