完美实现 Windows 下网络通信

Posted Zackary.Liu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了完美实现 Windows 下网络通信相关的知识,希望对你有一定的参考价值。

编译环境:DEV C++

配置编译器

Windows 下 实现 Socket 编译需要 ws2_32.lib 这个库的支撑,所以我们编译前应该配置下编译器,具体配置步骤如下:

Tools -> Compiler Options

加入 -l 链接,如图所示:

实现的功能

服务器端与客户端可以互相自由给对方发送消息,无需在意接收与发送的顺序(利用线程实现)!可以实现加法运算。如需其它的功能,可以自行补充,如:实现四则运算、文件传输等。

服务器程序

/*
	Name: TCP Server 
	Copyright: -lws2_32
	Author: Lance#
	Date: 18/05/18
	Description: TCP Server 
*/

#include <stdio.h>    
#include <winsock2.h> 
#include <windows.h>
#include <string.h>

#define PORT		8080  
#define BUFSIZE		1024

/* 客户端Socket与发送缓冲 */
SOCKET client;
unsigned char SendBuf[BUFSIZE+1];

enum{
	NoConnection,
	Connected,
}LinkStatus;

/* 客户端连接状态监控线程 */
DWORD WINAPI print_message(LPVOID arg)
{
	while(1){
		if(!LinkStatus){
			printf("	等待客户端连接 .... \\r\\n");
			sleep(1);
		}
	}
}

/* 服务器发送消息线程 */
DWORD WINAPI send_message(LPVOID arg)
{	
	while(1){
		memset(SendBuf, 0, 1024); 
		fgets(SendBuf, 1024, stdin);
    	send(client, SendBuf, 1024, 0);
	}
} 

int main(int argc, char* argv[])
{
    WSADATA wsaData;
    struct sockaddr_in sin_addr;
    struct sockaddr_in remoteAddr;
    unsigned char recvData[BUFSIZE+1];
	int nAddrlen = sizeof(remoteAddr);
	
	unsigned int num_l, num_r;
	unsigned char sum_buf[100] = {0};
	
	/* 线程标识 */
	HANDLE pthread;
	
    /* 启动 WSA */
    WORD sockVersion = MAKEWORD(2, 2);

    if (WSAStartup(sockVersion, &wsaData)){
    	perror("WSA boot failed!");
        return -1;
    }

    /* 创建服务端套接字 */
    SOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (server == INVALID_SOCKET){
        perror("socket error!");
        return -1;
    }

    /* 配置 sin_addr */
    sin_addr.sin_family = AF_INET;
    sin_addr.sin_port = htons(PORT);
    /* 可监听任意的地址 */
    sin_addr.sin_addr.S_un.S_addr = INADDR_ANY; 
    /* 监听指定的地址 */
//    sin_addr.sin_addr.S_un.S_addr = inet_addr("192.168.1.149"); 
    
    /* 绑定 */
    if (bind(server, (LPSOCKADDR)&sin_addr, sizeof(sin_addr)) == SOCKET_ERROR){
        perror("bind error!");
        return -1;
    }

    /* 监听 */
    if (listen(server, 100) == SOCKET_ERROR){
        perror("listen error!");
        return -1;
    }
    
    puts("服务器成功启动"); 
    
    /* 创建状态线程 */
    CreateThread(NULL,0,print_message,NULL,0,NULL);
    /* 创建消息线程 */
    pthread = CreateThread(NULL,0,send_message,NULL,0,NULL);

    while (1)
	{	
        LinkStatus = NoConnection;
        client = accept(server, (SOCKADDR *)&remoteAddr, &nAddrlen);
        LinkStatus = Connected;
        
        if (client == INVALID_SOCKET)
        {
            perror("accept error!");
            continue;
        }
        
        printf("客户端:%s 已连接\\r\\n", inet_ntoa(remoteAddr.sin_addr));

		while(1){

	        /* 数据接收 */
	        memset(recvData, 0, sizeof(recvData));
	        int ret = recv(client, recvData, 1024, 0);
	        if (ret > 0){
	            printf("Recv:	%s", recvData);
	            /* 实现加法运算,客户端发来  "%d + %d =" 形式的数据后,将结果返回至客户端 */
	            if(sscanf(recvData, "%d + %d =", &num_l, &num_r) == 2){
	            	sprintf(sum_buf, "%d + %d ,sum is %d", num_l, num_r, num_l + num_r);
	            	send(client, sum_buf, sizeof(sum_buf), 0);
	            	memset(sum_buf, 0, sizeof(sum_buf));
				}
			}else
	        	/* 客户端异常则断开当前连接 */
				goto Reconnect;
				
			/* 客户端要求退出的话则断开当前连接 */
			if(!strncmp(recvData, "quit", 4))
				goto Reconnect;
		}
		
	Reconnect:
		closesocket(client);
		puts("*** 客户端已断开");
    }

	/* 关闭服务器套接字 */
    closesocket(server); 
    WSACleanup();
    
    return 0;
}

客户端程序

/*
	Name: TCP Client 
	Copyright: -lws2_32
	Author: Lance#
	Date: 18/05/18
	Description: TCP Client
*/

#include <stdio.h>  
#include <winsock2.h>  
#include <Windows.h>  
#include <string.h>
  
#define PORT 		8080  
#define BUFSIZE		1024

unsigned char recvData[BUFSIZE+1] = {0};  

/* 线程标识 */
HANDLE pthread;

DWORD WINAPI recv_message(LPVOID arg)
{
	int res;
	
	while(1){
		memset(recvData, 0, 1024); 
		res = recv((SOCKET)arg, recvData, 1024, 0);
		if(res > 0)
			printf("Recv:	%s", recvData);
		else{
			printf("*** 服务器已退出(回车退出程序)");
			return 0;
		} 
	}
}
  
int main(int argc, char * argv[])  
{  
	unsigned char SendBuf[BUFSIZE+1] = {0};  
	WSADATA wsaData;
	SOCKADDR_IN addrServ;  
	
	if(argc != 2){
		puts("argc error");
		puts("Usage: <client.exe> <ip addr>");
		return -1;
	}

    /* 启动 WSA */
    WORD sockVersion = MAKEWORD(2, 2);

    if (WSAStartup(sockVersion, &wsaData)){
    	perror("WSA boot failed!");
        return -1;
    }
    
    /* 创建 socket */
    SOCKET client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  
    if (client == INVALID_SOCKET){  
        perror("socket failed");  
        return -1;  
    }  
    
    /* 配置 socket */
    addrServ.sin_family = AF_INET;  
    addrServ.sin_port = htons(PORT);  
	/* 配置服务器 IP */
    addrServ.sin_addr.S_un.S_addr = inet_addr(argv[1]);  
      
    /* 连接至服务器 */
    int ret = connect(client,(SOCKADDR*)&addrServ,sizeof(SOCKADDR));
    if (SOCKET_ERROR == ret){  
        perror("socket connect failed");  
        closesocket(client);  
        WSACleanup();  
        return -1;  
    }  
    
    /* 创建工作线程 */
	pthread = CreateThread(NULL,0 ,recv_message,(LPVOID)client,0,NULL);
	
	puts("客户端成功启动,输入\'quit\'关闭客户端"); 
    
    while(1)
	{
	    memset(SendBuf,0,sizeof(SendBuf));  
	    
	    fgets(SendBuf, 1024, stdin);
	    
	    ret = send(client, SendBuf, 1024, 0);  
	    if (SOCKET_ERROR == ret){  
	        closesocket(client);  
	        exit(0);
	    } 
		
		/* 客户端退出 */
		if(!strncmp(SendBuf, "quit", 4))
			goto Disconnect;
	}

Disconnect:  
    closesocket(client);  
    WSACleanup();  
    
    return 0;  
}  

运行结果演示

打开 CMD,进入可执行文件所在目录

执行 server.exe 运行服务器;
启动另一个 CMD,执行 client.exe 127.0.0.1 运行客户端。

双方可进行通信,效果如图:

以上是关于完美实现 Windows 下网络通信的主要内容,如果未能解决你的问题,请参考以下文章

Qt 无边框窗体改变大小 完美实现(全部自己实现)

使用EasyBCD完美实现Windows7与Linux双系统

使用片段着色器在特定位置绘制完美的水平线

运行/调试你的PHP代码

Windows Form简易计算器实现(下)

ActionBar的后退主页按钮无法使用片段