Server:
#include
#include"winsock2.h"
#include"WS2tcpip.h" //本程序用到地址转换函数inet_pton(),所以要包含该头文件
#include"process.h"
#include
#include
#include
//#include
#define PORT 65432 //定义要访问的服务器端口常量
#define MSG_SHOW 1
#define MSG_CREATE 2
#define MSG_JOIN 3
#define MSG_LEAVE 4
#define MSG_QUIT 5
#define MSG_EXIT 5
#define MSG_TALK 6
#pragma comment(lib,"ws2_32.lib")
using namespace std;
class MsgHead {
public:
int msgType;
int dataLength;
};
class MsgShow :public MsgHead
{
public:
MsgShow() {
msgType = MSG_SHOW;
dataLength = sizeof(MsgShow);
}
};
class MsgCreate :public MsgHead
{
public:
MsgCreate() {
msgType = MSG_SHOW;
dataLength = sizeof(MsgCreate);
}
};
class MsgJoin :public MsgHead
{
public:
MsgJoin() {
msgType = MSG_SHOW;
dataLength = sizeof(MsgJoin);
}
};
class MsgLeave :public MsgHead
{
public:
MsgLeave() {
msgType = MSG_SHOW;
dataLength = sizeof(MsgLeave);
}
};
class MsgExit :public MsgHead
{
public:
MsgExit() {
msgType = MSG_SHOW;
dataLength = sizeof(MsgExit);
}
};
class MsgTalk :public MsgHead
{
char buff[1024];
public:
MsgTalk() {
memset(buff, '\0', sizeof(buff));
msgType = MSG_TALK;
dataLength = sizeof(MsgTalk);
}
char* getBuff() {
return buff;
}
};
void dealWithData(MsgHead* msg,SOCKET sClient) {
if (msg->msgType == MSG_SHOW) {
cout << "显示聊天室" << endl;
}
else if (msg->msgType == MSG_CREATE){
cout << "创建聊天室" << endl;
}
else if (msg->msgType == MSG_JOIN) {
cout << "加入聊天室" << endl;
}
else if (msg->msgType == MSG_LEAVE) {
cout << "离开聊天室" << endl;
}
else if ((msg->msgType == MSG_QUIT ) || (msg->msgType == MSG_EXIT)) {
cout << "退出" << endl;
}
else if (msg->msgType == MSG_TALK) {
cout << "开始聊天" << endl;
//MsgTalk* msgtalk = (MsgTalk*)buff;
cout << ((MsgTalk*)msg)->getBuff() << endl;
}
}
int main()
{
SOCKET sock_server, newsock;
struct sockaddr_in addr, client_addr;
unsigned hThread;
/*初始化winsock DLL*/
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
cout << "加载winsock.dll失败!\n";
return 0;
}
/*创建套接字*/
// if ((sock_server=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET)
if ((sock_server = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
{
cout << "创建套接字失败!" << WSAGetLastError() << endl;
WSACleanup();
return 0;
}
/*绑定IP端口*/
int addr_len = sizeof(struct sockaddr_in);
memset((void*)&addr, 0, addr_len);
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
/*给监听套接字绑定地址*/
// if (bind(sock_server,(LPSOCKADDR)&addr,sizeof(addr))!=0)
if (bind(sock_server, (const sockaddr *)&addr, sizeof(addr)) != 0)
{
cout << "绑定地址失败!" << WSAGetLastError() << endl;
closesocket(sock_server);
WSACleanup();
return 0;
}
/*开始监听*/
if (listen(sock_server, 0) != 0)
{
cout << "listen函数调用失败!" << WSAGetLastError() << endl;
closesocket(sock_server);
WSACleanup();
return 0;
}
else
{
cout << "listenning......\n";
}
/*接收并处理客户连接*/
FD_SET fd_read; //fd_set 里面放的是socket,是一个socket集合
FD_ZERO(&fd_read);
FD_SET(sock_server, &fd_read);
FD_SET copy(fd_read);
while (true) {
const timeval tv = { 1,0 };
fd_read = copy;
//cout << fd_read.fd_count << endl;
int ret = select(NULL, &fd_read, NULL, NULL, &tv);//select会识别有没有网络事件发送,若没有就阻塞在这里。加了个timeval代表让他等一秒就往下执行
/*cout << fd_read.fd_count << endl;
cout << fd_read.fd_array[0] << endl;
cout << fd_read.fd_array[1] << endl;*/
int fdCount = fd_read.fd_count;
for (int i = 0;i < fdCount;i++) {
if (fd_read.fd_array[i] == sock_server) {
cout << 1 << endl;
sockaddr_in clientAddr;
int nlen = sizeof(sockaddr_in);
SOCKET sClient = accept(sock_server, (sockaddr*)&clientAddr, &nlen);
/* 第一个参数sockfd为服务器的socket描述字,
第二个参数addr为指向struct sockaddr* 的指针,用于返回客户端的协议地址,
第三个参数addrlen为协议地址的长度。*/
if (sClient == SOCKET_ERROR) {
cout << "接收客户端失败" << endl;
closesocket(sock_server);
return -1;
}
else cout << "连接客户端成功" << endl;
FD_SET(sClient, &fd_read);
FD_SET(sClient, ©);
}
else {
char msg[1024];
memset(msg, '\0', sizeof(msg));
int res = recv(fd_read.fd_array[i], msg, 20, 0);
dealWithData((MsgHead *) msg,fd_read.fd_array[i]);
if (res <= 0) {
FD_CLR(fd_read.fd_array[i], ©);
cout << "用户退出" << endl;
break;
}
}
}
}
closesocket(newsock);
closesocket(sock_server);
WSACleanup();
return 0;
}
void tcpsend(void* par)
{
int size;
SOCKET sock = (SOCKET)par;
while (true)
{
char msg[1000];
memset(msg, '\0', sizeof(msg));
if ((size = recv(sock, msg,99, 0)) < 0)
{
cout << "接收信息失败,错误码:" << WSAGetLastError() << endl;
break;
}
else if (size == 0)
{
break;
}
else //输出收到的数据
{
//将数据中的整型数据字段的值由网络字节顺序转换为主机字节顺序
//stud.examination = htonl(stud.examination);
cout << "收到的消息:" << msg << endl;;
}
}
}
Client:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PORT 65432
#define MSG_SHOW 1
#define MSG_CREATE 2
#define MSG_JOIN 3
#define MSG_LEAVE 4
#define MSG_QUIT 5
#define MSG_EXIT 5
#define MSG_TALK 6
#pragma comment(lib, "Ws2_32.lib")
using namespace std;
class MsgHead {
public:
int msgType;
int dataLength;
};
class MsgShow:public MsgHead
{
public:
MsgShow() {
msgType = MSG_SHOW;
dataLength = sizeof(MsgShow);
}
};
class MsgCreate :public MsgHead
{
public:
MsgCreate() {
msgType = MSG_SHOW;
dataLength = sizeof(MsgCreate);
}
};
class MsgJoin :public MsgHead
{
public:
MsgJoin() {
msgType = MSG_SHOW;
dataLength = sizeof(MsgJoin);
}
};
class MsgLeave :public MsgHead
{
public:
MsgLeave() {
msgType = MSG_SHOW;
dataLength = sizeof(MsgLeave);
}
};
class MsgExit :public MsgHead
{
public:
MsgExit() {
msgType = MSG_SHOW;
dataLength = sizeof(MsgExit);
}
};
class MsgTalk :public MsgHead
{
char buff[1024];
public:
MsgTalk() {
memset(buff, '\0', sizeof(buff));
msgType = MSG_TALK;
dataLength = sizeof(MsgTalk);
}
char* getBuff() {
return buff;
}
};
LPVOID chat(LPVOID ptr) {
SOCKET sClient = *(SOCKET*)ptr;
cout << "please input: show create join leave exit/quit" << endl;
while (1) {
char buff[1024];
gets_s(buff); //会清掉最后输的换行符
if (strcmp(buff, "show") == 0) {
//显示聊天室
}
else if (strcmp(buff, "join") == 0) {
//加入一个聊天室
}
else if (strcmp(buff, "create") == 0) {
//创建一个聊天室
}
else if (strcmp(buff, "talk") == 0) {
cout << "开始聊天" << endl;
MsgTalk msgTalk;
while (1) {
gets_s(msgTalk.getBuff(), 1000);
send(sClient, (const char*)&msgTalk, msgTalk.dataLength, 0);
}
}
}
}
int main() {
/*定义相关变量*/
int sock_client; //定义客户端套接字
struct sockaddr_in server_addr; //定义存放服务器端地址的结构变量
int addr_len = sizeof(struct sockaddr_in); //地址结构变量长度
/*初始化*/
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
cout << "加载winsock.dll失败!\n";
return 0;
}
/*创建套接字*/
if ((sock_client = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
cout << "创建套接字失败!错误代码:" << WSAGetLastError() << endl;
WSACleanup();
return 0;
}
/*输入服务器IP地址以及填写服务器地址结构*/
char IP[20];
cout << "请输入服务器地址:";
cin >> IP;
memset((void*)&server_addr, 0, addr_len);//地址结构清零
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
in_addr a;
inet_pton(AF_INET, IP, &a);
server_addr.sin_addr.s_addr = a.S_un.S_addr;//服务器IP地址
/*Connecting Server*/
SOCKET_ERROR;
if (connect(sock_client, (struct sockaddr*)&server_addr, addr_len) != 0)
{
cout << "Connecting Error!!" << WSAGetLastError() << endl;
closesocket(sock_client);
WSACleanup();
return 0;
}
chat(&sock_client);
//future futureResult = async(chat,&sock_client);
while (1) {
char buff[1000];
int ret = recv(sock_client, buff, 1024, 0);
if (ret > 0) {
}
else {
cout << "客户端接收数据失败" << endl;
}
}
//HANDLE = futureResult.get();
//WaitForSingleObject();
closesocket(sock_client);
WSACleanup();
return 0;
}