C语言-Socket实现双人网络通信

服务端
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”:
在这里插入图片描述
此错误参考

此代码中线程,参考文档

—End—

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值