您的位置:首页 > 理论基础 > 计算机网络

[Windows网络编程课设]南工程聊天室客户端源码

2016-09-20 18:46 309 查看
南工程聊天室客户端源码
南京工程学院通信工程学院的《Windows网络编程》一课的课程设计源码,聊天室的搭构需要服务器和客户端。服务器源码请看上一篇博文,都有贴出。备注也很详细,可以参考一下。不过作为聊天室功能也很多的,我这里贴出的代码功能实现的并不全面。如果有同学对此作出改进,希望可以交流一下。

MyMsg.h
#pragma once
/************************************************************
*  文件名:MyMsg.h
*  描述:  服务器和客户端共用的头文件,消息定义
*************************************************************/
#ifndef _MYMSG_H_
#define _MYMSG_H_

enum {
LOGIN_MSG,           //登录
LOGIN_MSG_RES,       //登录响应
QUERY_FQQ,           //查询单个好友QQ
QUERY_FQQ_RES,       //查询单个好友QQ的响应
TALK_MSG,             //聊天
REQUEST_ALL_FRD,      //请求所有qq好友信息
APPLY_ALL_FRD        //应答所有qq好友信息
};

struct LoginMsg {
unsigned char id;  //消息编号
char qq[6];        //登录ID号
};

struct LoginMsgResponse {
unsigned char id;  //消息编号
unsigned char isOK;
char reason[100];    //如果失败,则在此写入失败原因
};

struct FriendQqMsg {
unsigned char id;  //消息编号
char qq[6];
};

struct FriendQqMsgResponse {
unsigned char id;  //消息编号
unsigned char isOK;
};

struct TalkMsg {
unsigned char id;  //消息编号
char qq[6];
char fqq[6];
char info[200];
};

struct RequestAllFriend {
unsigned char id;   //消息编号
};

struct AllFriendMsg {
unsigned char id;  //消息编号
char qq[6];
};

#endif


MyTcp.cpp
/************************************************************
*  文件名:MyTCP.cpp
*  描述:  TCP/IP通信socket封装
*************************************************************/
#include <stdio.h>
#include <WinSock2.h>
#include "MyTools.h"
#pragma comment (lib, "ws2_32.lib")

#define PORT 5001
int ls;   //侦听套接字
int flag;//记录服务器或是客户端的标志

/*   描述: 初始化服务器或客户端, 该函数在使用中必需首先调用,客户端和服务器 */
int initSock(int IsServer)
{
WSADATA data;

if (WSAStartup(1, &data) <0)
printMsgExit("call WSAStartup() failure!");

ls = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ls < 0)
printMsgExit("创建套接字失败!");

flag = IsServer;
if (IsServer != 0)
{//服务器
struct sockaddr_in servAddr;
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(PORT);

if (bind(ls, (struct sockaddr *)&servAddr, sizeof(servAddr))<0) {
printMsg("bind套接字失败!\n");
return -1;
}

if (listen(ls, 10)<0) {
printMsg("listen套接字失败!\n");
return -1;
}
}

return 0;
}

/*   描述: 仅用于客户端, 连接服务器 */
int tcpConnect(const char *serverIP, unsigned short port)
{
struct sockaddr_in servAddr;

memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr(serverIP);
servAddr.sin_port = htons(port);

if (connect(ls, (struct sockaddr *)&servAddr, sizeof(servAddr))<0)
{
printMsgExit("连接服务器失败!\n");
}

return ls;
}

/* 描述: 发送数据 */
int tcpSend(unsigned int sock, const char *sendBuf, int sendBufLen)
{
int len = send(sock, sendBuf, sendBufLen, 0);
return len;
}

/* 描述: 接收数据 */
int tcpRecv(unsigned int sock, char *recvBuf, int recvBufLen)
{
int len = recv(sock, recvBuf, recvBufLen, 0);
return len;
}

void tcpClose(unsigned int sock)
{
closesocket(sock);
WSACleanup();
}


MyTcp.h
#pragma once
/************************************************************
*  文件名:MyTCP.h
*  描述:  TCP通信头文件
*************************************************************/
#ifndef _MYTCP_H_
#define _MYTCP_H_

int initSock(int IsServer);
int tcpConnect(const char *serverIP, unsigned short port);
int tcpAccept();
int tcpSend(unsigned int sock, const char *sendBuf, int sendBufLen);
int tcpRecv(unsigned int sock, char *recvBuf, int recvBufLen);
void tcpClose(unsigned int sock);

#endif


MyTools.cpp
/************************************************************
*  文件名:MyTools.cpp
*  描述:  共用的文件,工具函数定义
*************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "MyTools.h"

extern int flag;

void printMsg(const char * msg) {
if (flag)
printf("\t【南工服务器豪华版】%s", msg);
else
printf("\t【南工客户端豪华版】%s", msg);
}

void printInt(int value) {
if (flag)
printf("\t【南工服务器豪华版】%d", value);
else
printf("\t【南工客户端豪华版】%d", value);
}

void printMsgExit(const char * msg) {
printMsg(msg);
exit(0);
}

void printIntExit(int value) {
printInt(value);
exit(0);
}
MyTools.h
#pragma once
/************************************************************
*  文件名:MyTools.h
*  描述:工具函数定义
*************************************************************/
#ifndef _MYTOOLS_H_
#define _MYTOOLS_H_
void printMsgExit(const char * msg);
void printMsg(const char * msg);
void printInt(int value);
void printIntExit(int value);
#endif


TalkClient.cpp
/************************************************************
*  文件名:TalkClient.cpp
*  描述:  客户端入口,界面操作
*************************************************************/
#include <stdio.h>
#include <Windows.h>

#include "TalkClientService.h"

void displayMenu();
void exitProc();
void defProc();
void procMenu();

char serverip[6];

int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("请输入服务器的IP地址。。。\n");
return 0;
}
strcpy(serverip, argv[1]);
displayMenu();
procMenu();
while (1) Sleep(10000);
}

char ch;     //菜单选择
void displayMenu()
{
static int t = 1;
if (t++ == 1)
{
printf("\n\n\n\n\n");
printf("\n\t      @                                                             @        ");
printf("\n\t    @ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @      ");
printf("\n\t   @  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   @    ");
printf("\n\t  @   **      **  **********  **        **         ********   **  **     @   ");
printf("\n\t @    **      **  **          **        **        **      **  **  **      @  ");
printf("\n\t @    **      **  **          **        **        **      **  **  **       @  ");
printf("\n\t @    **********  **********  **        **        **      **  **  **       @  ");
printf("\n\t @    **      **  **          **        **        **      **  **  **       @  ");
printf("\n\t @    **      **  **          **        **        **      **              @  ");
printf("\n\t  @   **      **  **********  ********  ********   ********   @@  @@     @   ");
printf("\n\t   @   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  @    ");
printf("\n\t    @  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@      ");
printf("\n\t      @                                                             @        ");

printf("\n                                                             -----By Hins    ");
printf("\n\n\n\n\n\t\tPress 'Enter' to enter the menu......");           /*按任一键进入主菜单*/
}
getchar();                                 /*从键盘读取一个字符,但不显示于屏幕*/
system("cls"); /*清屏*/
printf("\n");
printf("\n");
printf("\n");
printf("\t************************************************\n");
printf("\t*                                              *\n");
printf("\t*         南工2016聊天客户端程序               *\n");
printf("\t*         Version 2.1     豪华版               *\n");
printf("\t*                                              *\n");
printf("\t*                                              *\n");
printf("\t*                                              *\n");
printf("\t*           1) 登录(L)                         *\n");
printf("\t*           2) 退出(e)                         *\n");
printf("\t*                      by---HinsShwan          *\n");
printf("\t************************************************\n");
printf("\n");
connectServer();
printf("\t您的选择是:");
ch = getchar();
}

void procMenu()
{
switch (ch)
{
case 'l':
case 'L':
case '1':
statusConnected();
break;

case 'e':
case 'E':
case '2':
exitProc();
break;

default:
defProc();
}
}

void exitProc()
{
printf("\t客户端程序已经终止!\n");
exit(0);
}

void defProc()
{
printf("\t 输入字符错误!\n");
}


TalkClientService.cpp
/************************************************************
*  文件名:TalkClientService.cpp
*  描述:  客户端业务实现
*************************************************************/
#include "MyTCP.h"
#include "MyTools.h"
#include "TalkClientService.h"
void myRecvThread();
#define PORT 5001

extern char serverip[6];

char qq[6] = { 0 };
char fqq[6] = { 0 };
int sock;

int status = STUS_START;

void mainProc()
{
while (1)
{

switch (status)
{
case STUS_CONNECTED:
statusConnected();
break;

case STUS_WAIT_LOGIN_RES:
printMsg("等待服务器响应..........\n");
Sleep(1000);
break;

case STUS_LOGINED:
statusLogined();
break;

case STUS_WAIT_QUERY_FQQ_RES:
printMsg("等待服务器响应..........\n");
Sleep(1000);
break;

case STUS_TALK:
statusTalk();
break;
case STUS_WAIT_QUERY_ALLQQ_RES:
printMsg("等待服务器响应..........\n");
Sleep(1000);
break;
}
}
}

void statusTalk()
{
printMsg("退出聊天(Exit) 我说>>");
setbuf(stdin, NULL);   //清空键盘缓冲区

char buf[1024] = { 0 };
gets_s(buf);
if (strcmp(buf, "Exit") == 0)
{
printMsg("客户端已经退出!\n");
statusLogined();
}

else
{
struct TalkMsg msg;

msg.id = TALK_MSG;
strcpy(msg.qq, qq);
strcpy(msg.fqq, fqq);
strcpy(msg.info, buf);
status = 5;
tcpSend(sock, (const char *)&msg, sizeof(msg));
}

return;
}

void statusLogined()
{
char buf0[10] = { 0 };
int rt = 0;
while (rt == 0)
{
memset(buf0, 0, sizeof(buf0));
printMsg("显示在线好友(L)|找好友聊天(T)|退出(E) 默认(T)>>");
setbuf(stdin, NULL);   //清空键盘缓冲区
gets_s(buf0);
if (strcmp(buf0, "T") == 0 || strcmp(buf0, "t") == 0)
{
printMsg("选择聊天好友......\n");
while (1)
{
printMsg("输入聊天好友QQ号(最多不超过5位):  退出请输入“quit”");
char tmp[1024];
scanf("%s", tmp);
if (strlen(tmp) > 5)
{
printMsg("您输入的qq号长度大于5个,请重新输入\n");
}
else if (strcmp(tmp, qq) == 0)
{
printMsg("您输入的qq号是自己号码,难道您要自言自语吗?::) 请重新输入\n");
}
else if (strcmp(tmp, "quit") == 0)
break;
else
{   //发送要聊天的好友QQ号给服务器
struct FriendQqMsg msg;
msg.id = QUERY_FQQ;
strcpy(msg.qq, tmp);
strcpy(fqq, tmp);
status = STUS_WAIT_QUERY_FQQ_RES;
tcpSend(sock, (const char *)&msg, sizeof(msg));
rt = 1;
break;
}
}
}
else if (strcmp(buf0, "L") == 0 || strcmp(buf0, "l") == 0)
{
char buf2[10] = { 0 };
memset(buf2, 0, sizeof(buf2));
struct RequestAllFriend res;
res.id = REQUEST_ALL_FRD;
memcpy(buf2, &res, sizeof(res));
tcpSend(sock, (const char*)buf2, sizeof(buf2));
status = STUS_WAIT_QUERY_ALLQQ_RES;
Sleep(100);
}
else if (strcmp(buf0, "E") == 0 || strcmp(buf0, "e") == 0)
{
printMsg("客户端已经退出!\n");
exit(0);
}
else
{
printMsg("输入内容错误(手抖了吧-_-),请重新输入\n");

}

};

}

void connectServer()
{
printMsg("开始连接服务器......\n");
initSock(0);  //客户端
sock = tcpConnect(serverip, PORT);
printMsg("连接服务器成功!\n");

//创建一个线程用于接收服务器发送的信息
DWORD threadId;
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)myRecvThread, NULL, 0, &threadId);
}

//创建接收线程专用于接收并处理服务器返回的收数据
void myRecvThread()
{
char buf[1024] = { 0 };
while (1)
{
memset(buf, 0, sizeof(buf));
tcpRecv(sock, buf, sizeof(buf));
unsigned char id = (unsigned char)buf[0];
switch (id)
{
case LOGIN_MSG_RES:
procLoginMsgResponse((struct LoginMsgResponse *)buf);
break;

case QUERY_FQQ_RES:
procFriendQqMsgResponse((struct FriendQqMsgResponse *)buf);
break;

case TALK_MSG:
procTalkMsg((struct TalkMsg *)buf);
break;
case APPLY_ALL_FRD:
procApplyAllFriend((struct AllFriendMsg *)buf);
break;

}
}
sprintf(buf, "结束myRecvThread线程:%d.........\n");
printMsg(buf);
exit(0);
}

void statusConnected()
{
printMsg("\n\t请输入登录信息\n");

while (1)
{
printMsg("本机的QQ号(最多不超过5位数字):");
char tmp[1024];
scanf("%s", tmp);
int  i;
if (strlen(tmp)>5)
{
printMsg("您输入的qq号长度大于5个,请重新输入\n");
continue;
}

for (i = 0;i<strlen(tmp);i++)
{
if (tmp[i] >= '0' && tmp[i] <= '9')
{
continue;
}
else
break;
}

if (i == strlen(tmp))
{
strcpy(qq, tmp);
break;

}
else
{
printMsg("输入信息有误,请重新输入\n");
continue;
}

}

struct LoginMsg msg;
msg.id = LOGIN_MSG;
status = STUS_WAIT_LOGIN_RES;
strcpy(msg.qq, qq);
tcpSend(sock, (const char *)&msg, sizeof(msg));
mainProc(); //进入主处理程序
return;
}

void procLoginMsgResponse(struct LoginMsgResponse *msg)
{
if (msg->isOK == 1)
{
printMsg("登录成功!\n");
status = STUS_LOGINED;//已登录状态
}
else
{
printMsg("登录失败!\n");
printMsgExit(msg->reason);
printf("\n");
}
}

void procFriendQqMsgResponse(struct FriendQqMsgResponse *msg)
{
if (msg->isOK == 1)
{
printMsg("好友目前在线,可以开始聊天...\n");
status = STUS_TALK;
}
else
{
printMsg("好友不存在啊,再换个人试试!\n");
status = STUS_LOGINED;
}
}

void procTalkMsg(struct TalkMsg *msg)
{
char buf[1024] = { 0 };

if (strcmp(msg->qq, fqq) == 0)
{//表示是自己发起的聊天,仅仅显示信息即可
printf("\n");
sprintf(buf, "%s说>>%s", fqq, msg->info);
printMsg(buf);
}
else
{//是陌生人发起的聊天
printf("\n");
sprintf(buf, "%s说>>%s", msg->qq, msg->info);
printMsg(buf);
}
}

void procApplyAllFriend(struct AllFriendMsg *msg)
{<pre name="code" class="html">#pragma once
/************************************************************
*  文件名:TalkClientService.h
*  描述:  客户端业务层函数声明
*************************************************************/
#ifndef _TALKCLIENTSERVICE_H_
#define _TALKCLIENTSERVICE_H_
#include <Windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "MyMsg.h"

void connectServer();
void procLoginMsgResponse(struct LoginMsgResponse *msg);
void procFriendQqMsgResponse(struct FriendQqMsgResponse *msg);
void procTalkMsg(struct TalkMsg *msg);
void statusConnected();
void statusLogined();
void statusTalk();
void procApplyAllFriend(struct AllFriendMsg *msg);

/** 客户端状态 **/
enum {
STUS_START,
STUS_CONNECTED,
STUS_WAIT_LOGIN_RES,
STUS_LOGINED,
STUS_WAIT_QUERY_FQQ_RES,
STUS_TALK,
STUS_WAIT_QUERY_ALLQQ_RES
};

#endif


char buf[100] = { 0 };sprintf(buf, "%s", msg->qq);printMsg("在线的QQ好友: \n");printMsg(buf);printf("\n");status = STUS_LOGINED;}


TalkClientService.h
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息