【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();

}

时间: 2024-08-11 03:32:03

【tcp-ip学习总结】基于udp的多人聊天室,带有登录注册功能的相关文章

javaweb学习总结——基于Servlet+JSP+JavaBean开发模式的用户登录注册

一.Servlet+JSP+JavaBean开发模式(MVC)介绍 Servlet+JSP+JavaBean模式(MVC)适合开发复杂的web应用,在这种模式下,servlet负责处理用户请求,jsp负责数据显示,javabean负责封装数据. Servlet+JSP+JavaBean模式程序各个模块之间层次清晰,web开发推荐采用此种模式. 这里以一个最常用的用户登录注册程序来讲解Servlet+JSP+JavaBean开发模式,通过这个用户登录注册程序综合案例,把之前的学过的XML.Xpat

JavaWeb学习总结(基于Servlet+JSP+JavaBean开发模式的用户登录注册)

一.Servlet+JSP+JavaBean开发模式(MVC)介绍 Servlet+JSP+JavaBean模式(MVC)适合开发复杂的web应用,在这种模式下,servlet负责处理用户请求,jsp负责数据显示,javabean负责封装数据. Servlet+JSP+JavaBean模式程序各个模块之间层次清晰,web开发推荐采用此种模式. 这里以一个最常用的用户登录注册程序来讲解Servlet+JSP+JavaBean开发模式,通过这个用户登录注册程序综合案例,把之前的学过的XML.Xpat

基于swoole实现多人聊天室

核心的swoole代码 基本的cs(client-sercer)结构不变,这里利用的是redis的哈希和set来储存和分组;从而达到了分组,统计,定时推送等功能;最后利用onclose事件来剔除断开的连接,全部代码如下:(没做前端,就不展示了) 核心的swoole ws.php <?php namespace app\common; require_once 'Predis.php'; require_once 'Task.php'; /** * socket面向对象的编译 */ class W

ICMP和arp协议以及tcp/ip学习

ICMP:http://blog.csdn.net/tigerjibo/article/details/7356936 ARP:http://blog.csdn.net/tigerjibo/article/details/7351992 IP分片:http://www.vants.org/?post=106 TSO/GSO linux内核源码剖析 udp: http://modernrobber.blog.163.com/blog/static/214636320074305183395/ ht

Photon服务器引擎(二)socket/TCP/UDP基础及Unity聊天室的实现

Photon服务器引擎(二)socket/TCP/UDP基础及Unity聊天室的实现 我们平时说的最多的socket是什么呢,实际上socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API). 通过Socket,我们才能使用TCP/IP协议.实际上,Socket跟TCP/IP协议没有必然的联系.Socket编程接口在设计的时候,就希望也能适应其他的网络协议.所以说,Socket的出现只是使得程序员更方便地使用TCP/IP协议栈而已,是对TCP/IP协议的抽象,

对基于Servlet+JSP+JavaBean开发模式的用户登录注册的升级

还记得我前面所写的博文基于Servlet+JSP+JavaBean开发模式的用户登录注册吗?我们以前是创建代表数据库的xml文件来保存用户信息的,现在我们已经学习了数据库相关的知识,所以应把xml换成数据库,升级成数据库应用. 我们在把以前的工程复制并拷贝时,假设以前的工程名是day09_user,现复制一份并拷贝,重新修改工程名为day14_user,此刻将其直接部署在tomcat服务器上,那么day14_user这个JavaWeb应用映射的虚拟目录仍然是"/day09_user",

基于EPOLL模型的局域网聊天室和Echo服务器

一.EPOLL的优点 在Linux中,select/poll/epoll是I/O多路复用的三种方式,epoll是Linux系统上独有的高效率I/O多路复用方式,区别于select/poll.先说select/poll的缺点,以体现epoll的优点. select: (1)可监听的socket受到限制,在32位的系统中,默认最大值为1024. (2)采用轮询方式,当要监听的sock数量很大时,效率低. (3)随着要监听socket数据的增加,要维护一个存放大量fd的数据结构,系统开销太大. pol

基于LBS的多人聊天

基于LBS的多人聊天,布布扣,bubuko.com

基于Select模型的混乱聊天室v1.0

最近在无聊完成了一个简单的基于select模型的匿名聊天室程序,均使用C++开发 服务器工作原理: 每接收一条客户端的信息,就将遍历所有的socket,并将该信息发给所有的客户端. 客户端使用两条线程,一个是接收服务端信息的线程,一个是等待阻塞输入的线程,获得输入时,将输入发送到服务器. 项目源码:https://github.com/coderguang/Chat 版本为v2.0的release. 其中ComLib也在github上 服务器核心代码: int main(int argc,cha