服务端
1、负责转发双方的消息
|----1.1、接收客户端A的消息,并转发给客户端B
|----1.2、接收客户端B的消息,并转发给客户端A
客户端
1、可以发送消息给对方
2、可以接受对方的消息
关于线程
1、服务的与客户端均使用了线程,在客户端中主线程负责我方发送消息,另一个线程(函数名:ThreadReceive)用于接收对方的消息并显示在控制台(底部给出参考链接)。
工作流程图
详细流程
1、因为是两个客户端聊天,所以在服务端需要得到两个客户端的Socket。服务端首先等待第一个客户端连接,第一个客户端连接成功后,再等待第二个客户端连接,双方都连接后,服务端开始工作(上图绿色字体)。
2、客户端会有一个单独的线程来接收来自服务器的消息(其实接收的是对方的消息,由服务端转发)
注:服务的作用是负责转发两个客户端之间的消息,让双方都能收到对方的消息。所以服务端是等待两次Socket连接,第一次是第一个客户端,第二次是第二个客户端,在只有一个客户端连接的情况下,发消息并没有意义。
运行效果图
客户端代码(Client[32bit]V1.4.cpp)
#include <WinSock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <process.h>
#include <windows.h>
#pragma comment(lib,"ws2_32.lib")
/* * * * * * * * * * * * * * * * Client * * * * * * * * *
*夏雨程_YKC
*alanlw21@qq.com
*
*Dev-C++5.11编译报错附加:-lwsock32
* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void ThreadReceive(PVOID param);
void SendReceiveException(int e);
SOCKET ClientSocket = INVALID_SOCKET;
char name[18] = "";
int main(void)
{
system("title Client V1.4");
system("mode con cols=60 lines=23");
system("color 9F");
SOCKADDR_IN ServerAddr = { 0 };
WSADATA wsaData = { 0 };
USHORT uPort = 47168;//服务端端口
if (WSAStartup(MAKEWORD(2, 2), &wsaData))
{
printf("WSAStartup failed with error code: %d\n", WSAGetLastError());system("pause");
return -1;
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
printf("wVersion was not 2.2\n");system("pause");
return -1;
}
ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ClientSocket == INVALID_SOCKET) {
printf("socket failed with error code: %d\n", WSAGetLastError());system("pause");
return -1;
}
//服务器地址:127.0.0.1
char IP[20] = "127.0.0.1";
printf("请输入你的昵称:");
gets(name);
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(uPort);
ServerAddr.sin_addr.S_un.S_addr = inet_addr(IP);
printf("\n正在等待对方链接,请稍等...\n");
if (SOCKET_ERROR == connect(ClientSocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr))) {
printf("connect failed with error code: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
MessageBox(NULL,TEXT("链接服务器失败!"),TEXT("Error"),MB_OK|MB_ICONWARNING);
return -1;
}else{
printf("链接成功...\n\n\n");
}
char buffer[1024] = {0};
int iRecvLen = 0;
int iSnedLen = 0;
_beginthread(ThreadReceive, 0, NULL); //启动线程
iSnedLen = send(ClientSocket, name, strlen(name), 0);
SendReceiveException(iSnedLen);
while (1)
{
memset(buffer, 0, sizeof(buffer));
printf("My:"); gets(buffer);
iSnedLen = send(ClientSocket, buffer, strlen(buffer), 0);
SendReceiveException(iSnedLen);
}
closesocket(ClientSocket);
WSACleanup();
printf("\n通讯结束!\n");
system("pause");
return 0;
}
void ThreadReceive(PVOID param)
{
char buffer[1024] = {0};
int iRecvLen = 0;
char nameOther[32] = { 0 };
iRecvLen = recv(ClientSocket, nameOther, sizeof(nameOther), 0);
SendReceiveException(iRecvLen);
strcat(nameOther, "\0");
while(true)
{
memset(buffer, 0, sizeof(buffer));
iRecvLen = recv(ClientSocket, buffer, sizeof(buffer), 0);
SendReceiveException(iRecvLen);
strcat(buffer, "\0");
printf("\r \r【%s】:%s", nameOther,buffer);
printf("\nMy:");
}
}
void SendReceiveException(int e)
{
if(SOCKET_ERROR == e)
{
printf("\n\nsend failed with error code: %d\n", WSAGetLastError());
printf("提示:链接异常或对方可能断开了链接!\n\n");
closesocket(ClientSocket); //关闭客户端套接字
WSACleanup(); //释放DLL
MessageBox(NULL,TEXT("链接异常或对方可能断开了链接!"),TEXT("提示"),MB_OK|MB_ICONWARNING);
system("pause");
exit(-1);
}
}
服务端代码(Server[32bit]V1.3.cpp)
#include <WinSock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <process.h>
#include <windows.h>
#pragma comment(lib,"ws2_32.lib")
/* * * * * * * * * * * * * * * * Server * * * * * * * * *
*夏雨程_YKC
*alanlw21@qq.com
*
*Dev-C++5.11编译报错附加:-lwsock32
* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
typedef struct Client{
SOCKET ServerSocket;
SOCKET ClientSocket01;
SOCKET ClientSocket02;
}CLS;
int init(CLS *pSer);
void CreatSocket(CLS *pcls);
void ThreadStart(CLS *pcls);
unsigned __stdcall ThreadReceive01(void* pCls);
unsigned __stdcall ThreadReceive02(void* pCls);
bool SendReceiveException(int e, CLS *p);
char Tempbuffer1[1024] = {0};
char Tempbuffer2[1024] = {0};
int main(void)
{
system("title Server V1.3");
system("color 1E");
CLS cls;
CLS *pcls = &cls;
while(true)
{
init(pcls);
CreatSocket(pcls);
ThreadStart(pcls);
}
while(true);
closesocket(pcls->ClientSocket01);
closesocket(pcls->ClientSocket02);
closesocket(pcls->ServerSocket);
WSACleanup();
return 0;
}
int init(CLS *pSer)
{
SOCKADDR_IN ServerAddr = { 0 };
pSer->ServerSocket = INVALID_SOCKET;
USHORT uPort = 47168;
WSADATA wsaData = { 0 };
if (WSAStartup(MAKEWORD(2, 2), &wsaData)){
printf("WSAStartup failed with error code: %d\n", WSAGetLastError());system("pause");
return -1;
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2){
printf("Version was not 2.2\n");
MessageBox(NULL,TEXT("Version was not 2.2(version Error)"),TEXT("Error"),MB_OK|MB_ICONWARNING);
system("pause");
return -1;
}
pSer->ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (pSer->ServerSocket == INVALID_SOCKET) {
printf("socket failed with error code: %d\n", WSAGetLastError());
MessageBox(NULL,TEXT("The initialization server failed!(socket function Error)"),TEXT("Error"),MB_OK|MB_ICONWARNING);
system("pause");
return -1;
}
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(uPort);//服务器监听端口
ServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
if (SOCKET_ERROR == bind(pSer->ServerSocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr))){
printf("bind failed with error code: %d\n", WSAGetLastError());
closesocket(pSer->ServerSocket);system("pause");
return -1;
}
if (SOCKET_ERROR == listen(pSer->ServerSocket, 3))
{
printf("listen failed with error code: %d\n", WSAGetLastError());
closesocket(pSer->ServerSocket);
WSACleanup();system("pause");
return -1;
}
}
void CreatSocket(CLS *pcls)
{
pcls->ClientSocket01 = INVALID_SOCKET;
pcls->ClientSocket02 = INVALID_SOCKET;
SOCKADDR_IN ClientAddr01 = { 0 };
SOCKADDR_IN ClientAddr02 = { 0 };
printf("\nwaiting connect.....\n\n");
int ClientAddrLength01 = sizeof(ClientAddr01);
int ClientAddrLength02 = sizeof(ClientAddr02);
pcls->ClientSocket01 = accept(pcls->ServerSocket, (SOCKADDR*)&ClientAddr01, &ClientAddrLength01);//等待客户端1链接...
printf("Client01 link to success, wait for Client02 link...\n");
pcls->ClientSocket02 = accept(pcls->ServerSocket, (SOCKADDR*)&ClientAddr02, &ClientAddrLength02);//等待客户端2链接...
printf("Client02 link to success,Start connect.\n\n");
if (pcls->ClientSocket01 == INVALID_SOCKET || pcls->ClientSocket02 == INVALID_SOCKET) {
printf("accept failed with error code: %d\n", WSAGetLastError());
closesocket(pcls->ServerSocket);
WSACleanup();//释放dll资源
MessageBox(NULL,TEXT("接收两个客户端出错,请重启服务器!"),TEXT("Error"),MB_OK|MB_ICONWARNING);
exit(-1);
}
}
void ThreadStart(CLS *pcls)
{
HANDLE hThread01;
HANDLE hThread02;
unsigned threadID01;unsigned threadID02;
printf("双方连接成功,开始聊天...\n\n");
hThread01 = (HANDLE)_beginthreadex( NULL, 0, &ThreadReceive01, pcls, 0, &threadID01 );
hThread02 = (HANDLE)_beginthreadex( NULL, 0, &ThreadReceive02, pcls, 0, &threadID02 );
WaitForSingleObject(hThread01, INFINITE);
WaitForSingleObject(hThread02, INFINITE);
CloseHandle(hThread01);
CloseHandle(hThread02);
}
//线程1-客户端01
unsigned __stdcall ThreadReceive01(void* pCls)
{
int isError = 0;
bool flag = true;
CLS *p = (CLS*)pCls;
char name[20] = { 0 };
isError = recv(p->ClientSocket01, name, sizeof(name), 0);
if(SendReceiveException(isError, p))flag=false;
isError = send(p->ClientSocket02, name, strlen(name), 0);
if(SendReceiveException(isError, p))flag=false;
printf("用户:%s---上线\n\n",name);
while(flag)
{
memset(Tempbuffer1, 0, sizeof(Tempbuffer1));
isError = recv(p->ClientSocket01, Tempbuffer1, sizeof(Tempbuffer1), 0);
if(SendReceiveException(isError, p))flag=false;
strcat(Tempbuffer1, "\0");
printf("【%s】:%s\n",name,Tempbuffer1);
isError = send(p->ClientSocket02, Tempbuffer1, strlen(Tempbuffer1), 0);
if(SendReceiveException(isError, p))flag=false;
}
}
//线程2-客户端02
unsigned __stdcall ThreadReceive02(void* pCls)
{
int isError = 0;
bool flag = true; //判断错误
CLS *p = (CLS*)pCls;
// 接收客户端02的用户名
char name[20] = { 0 };
isError = recv(p->ClientSocket02, name, sizeof(name), 0);
if(SendReceiveException(isError, p))flag=false;
isError = send(p->ClientSocket01, name, strlen(name), 0);
if(SendReceiveException(isError, p))flag=false;
printf("用户:%s---上线\n\n",name);
while(flag)
{
memset(Tempbuffer2, 0, sizeof(Tempbuffer2));
isError = recv(p->ClientSocket02, Tempbuffer2, sizeof(Tempbuffer2), 0);
if(SendReceiveException(isError, p))flag=false;
strcat(Tempbuffer2, "\0");
printf("【%s】:%s\n",name,Tempbuffer2);
isError = send(p->ClientSocket01, Tempbuffer2, strlen(Tempbuffer2), 0);
if(SendReceiveException(isError, p))flag=false;
}
}
bool SendReceiveException(int e, CLS *p)
{
if(SOCKET_ERROR == e)
{
printf("send failed with error code: %d\n", WSAGetLastError());
closesocket(p->ServerSocket);
closesocket(p->ClientSocket01);
closesocket(p->ClientSocket02);
printf("\nException function:User disconnected or error,Close all Sockets!But no DLL file is freed.\n");
return true;
}
return false;
}
关于编译时可能遇到的问题
此程序是在Dev-C++5.11下编译的,如果遇到报错:
则添加“-lwsock32”:
此错误参考