[网络编程]Socket实现Linux服务器和windows客户端&linux客户端的通信

以下代码测试环境为:

服务器:CentOS 7.5 64位

客户端1:Ubuntu 16.04 LTS 

客户端2:Win10 Server(服务器主机)

Socket实现Linux服务器和windows客户端&linux客户端的通信

1.实现Linux服务器向windows客户端和Linux客户端发送数据

1.1 Linux服务器端

1.1.1 Demo

1.1.2 特别说明

1.2 Linux客户端

1.2.1 Demo

1.2.2 特别说明

1.3 Windows客户端

1.3.1 Demo

1.3.2 特别说明

1.4 运行结果

1.4.1 分别在三个环境下编译对应代码得到可执行文件

1.4.2 启动服务器端LinuxServer

1.4.3 启动Linux客户端LinuxClient

1.4.4 重新启动服务端LinuxServer

1.4.5 启动Windows客户端LinuxClient

2.实现Linux服务器和Windows客户端&Linux客户端双向发送与接收的“回声服务器”

2.1 Linux 服务器代码

2.2 Windows客户端代码

2.3 Linux客户端代码

3. 实现Linux服务端和windows客户端&Linux客户端的循环通信

3.1 Linux 服务器代码

3.2 Windows 客户端代码

3.3 Linux 客户端代码

 


1.实现Linux服务器向windows客户端和Linux客户端发送数据

效果:服务器向客户端发送字符串“OKK!!!!!!!!!”,服务器接着关闭socket

端口:设置使用990端口发送,需要配置安全组规则,不懂可以搜索对应的服务器安全组配置(例如搜索腾讯云安全组配置)

1.1 Linux服务器端

1.1.1 Demo

// LinuxServer.cpp
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(){
    //创建套接字
    int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    //将套接字和IP、端口绑定
    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));  //每个字节都用0填充
    serv_addr.sin_family = AF_INET;  //使用IPv4地址
    serv_addr.sin_addr.s_addr = inet_addr("172.16.0.5");  //具体的IP地址
    serv_addr.sin_port = htons(990);  //端口
    bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

    //进入监听状态,等待用户发起请求
    listen(serv_sock, 20);

    //接收客户端请求
    struct sockaddr_in clnt_addr;
    socklen_t clnt_addr_size = sizeof(clnt_addr);
    int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);

    //向客户端发送数据
    char str[] = "okk!!!!!!!!!!!!!!!!!!!!";
    write(clnt_sock, str, sizeof(str));
   
    //关闭套接字
    close(clnt_sock);
    close(serv_sock);

    return 0;
}

1.1.2 特别说明

serv_addr.sin_addr.s_addr = inet_addr("172.16.0.5");  //具体的IP地址

这里使用的IP是云服务器主机商提供的内网IP,不是公网IP

以我刚开的腾讯云服务器为例(阿里云上的香港服务器已经变成了垃圾,数据包全部被拦截),腾讯提供了两个IP:

公网IP:129.204.119.105

内网IP:172.16.0.5

服务器端要使用内网的IP,而客户端要使用公网的IP才能找到服务器

1.2 Linux客户端

1.2.1 Demo

// LinuxClient.cpp
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

int main(){
    //创建套接字
    int sock = socket(AF_INET, SOCK_STREAM, 0);

    //向服务器(特定的IP和端口)发起请求
    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));  //每个字节都用0填充
    serv_addr.sin_family = AF_INET;  //使用IPv4地址
    serv_addr.sin_addr.s_addr = inet_addr("129.204.119.105");  //具体的IP地址
    serv_addr.sin_port = htons(990);  //端口
    connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
   
    //读取服务器传回的数据
    char buffer[40];
    read(sock, buffer, sizeof(buffer)-1);
   
    printf("Message form server: %s\n", buffer);
   
    //关闭套接字
    close(sock);

    return 0;
}

1.2.2 特别说明

 

这里客户端使用的IP是服务器的公网IP,使用的端口和服务器开放的TCP&IPV4服务端口一致均为990

 

1.3 Windows客户端

1.3.1 Demo

// WindowsClinet.cpp
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")  //加载 ws2_32.dll

int main(){
    //初始化DLL
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);

    //创建套接字
    SOCKET sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

    //向服务器发起请求
    sockaddr_in sockAddr;
    memset(&sockAddr, 0, sizeof(sockAddr));  //每个字节都用0填充
    sockAddr.sin_family = PF_INET;
    sockAddr.sin_addr.s_addr = inet_addr("129.204.119.105");
    sockAddr.sin_port = htons(990);
    connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));

    //接收服务器传回的数据
    char szBuffer[MAXBYTE] = {0};
    recv(sock, szBuffer, MAXBYTE, NULL);

    //输出接收到的数据
    printf("Message form server: %s\n", szBuffer);

    //关闭套接字
    closesocket(sock);

    //终止使用 DLL
    WSACleanup();

    system("pause");
    return 0;
}

1.3.2 特别说明

这里客户端使用的IP是服务器的公网IP,使用的端口和服务器开放的TCP&IPV4服务端口一致均为990

1.4 运行结果

要说明的是,这是最简单的通信,目前是单方向通信,接下来会进行双向通信

而且上面代码的逻辑也就是服务器端在发送了数据之后,就会退出,目前不能进行循环通信

所以在验证这三段代码能够正常工作的时候,按以下流程:

1.4.1 分别在三个环境下编译对应代码得到可执行文件

LinuxServer, WindowsClient, LinuxClient

1.4.2 启动服务器端LinuxServer

1.4.3 启动Linux客户端LinuxClient

验证能否接收到字符串“okk!!!!!!!!!!!!!!!!!!!!”

可以看到,此时Linux服务器也自动退出:

1.4.4 重新启动服务端LinuxServer

1.4.5 启动Windows客户端LinuxClient

验证能否接收到字符串“okk!!!!!!!!!!!!!!!!!!!!”

到目前为止,实现了1的功能,即Linux服务器和Linux客户端和windows客户端单向通信

2.实现Linux服务器和Windows客户端&Linux客户端双向发送与接收的“回声服务器”

回声服务器是指服务器在接收客户端发来的消息之后,将消息返回给客户端,好像客户端的声音又被传回

2.1 Linux 服务器代码

// LinuxServer.c 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define BUFSIZE 50
 
int main(){
    int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);


    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));  
    serv_addr.sin_family = AF_INET;  
    serv_addr.sin_addr.s_addr = inet_addr("172.16.0.5");  
    serv_addr.sin_port = htons(990);  
    bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

    
    listen(serv_sock, 20);  

    
    struct sockaddr_in clnt_addr;
    socklen_t clnt_addr_size = sizeof(clnt_addr);
    int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
    
  
	char strBuffer[BUFSIZE]; 
	int dataLength = read(clnt_sock, strBuffer, sizeof(strBuffer)-1);  
	printf("The server has already got the data from the client: %s\n", strBuffer);
//	char echoStr[BUFSIZE+10] = "Get data from Client: ";
//	memset(echoStr, '\0', sizeof(echoStr));
//	strcat(echoStr, strBuffer);
	
   
//    write(clnt_sock, echoStr, dataLength+strlen(echoStr)+1);  
	write(clnt_sock, strBuffer, dataLength);
	printf("Has already sent the data to the client");

    close(clnt_sock);
    close(serv_sock);

    return 0;
} 

 

2.2 Windows客户端代码

// WindowsClient.c

#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")  //加载 ws2_32.dll

#define BUF_SIZE 100

int main(){
    //初始化DLL
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);

    //创建套接字
    SOCKET sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

    //向服务器发起请求
    sockaddr_in sockAddr;
    memset(&sockAddr, 0, sizeof(sockAddr));  //每个字节都用0填充
    sockAddr.sin_family = PF_INET;
    sockAddr.sin_addr.s_addr = inet_addr("129.204.119.105");
    sockAddr.sin_port = htons(990);
    connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));
    //获取用户输入的字符串并发送给服务器
    char bufSend[BUF_SIZE] = {0};
    printf("Input a string: ");
    scanf("%s", bufSend);
    send(sock, bufSend, strlen(bufSend), 0);
    //接收服务器传回的数据
    char bufRecv[BUF_SIZE] = {0};
    recv(sock, bufRecv, BUF_SIZE, 0);

    //输出接收到的数据
    printf("Message form server: %s\n", bufRecv);

    //关闭套接字
    closesocket(sock);

    //终止使用 DLL
    WSACleanup();
	printf("Message has been achieved, the Client now gonna cloese");
    system("pause");
    return 0;
}

2.3 Linux客户端代码

这个有时间再写,目前主要是要实现windows的客户端到linux服务端的通信

 

3. 实现Linux服务端和windows客户端&Linux客户端的循环通信

3.1 Linux 服务器代码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define BUFSIZE 50

int main(){
    int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);


    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("172.16.0.5");
    serv_addr.sin_port = htons(990);
    bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));


    listen(serv_sock, 20);


    struct sockaddr_in clnt_addr;
    socklen_t clnt_addr_size = sizeof(clnt_addr);
    int clnt_sock = -1;
    do {
         clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
         if (clnt_sock < 0) {
             printf("Connected Error, re-try to get connected with client ... \n");
         }
    } while(clnt_sock < 0);
    while(1) {
        char strBuffer[BUFSIZE];
        int dataLength = read(clnt_sock, strBuffer, sizeof(strBuffer)-1);
        if (dataLength < 0) {
            printf("Read Error ... \n");
            continue;
        }
        printf("The server has already got the data: %s\n", strBuffer);


        int writeFlag = write(clnt_sock, strBuffer, dataLength);
        if (writeFlag < 0) {
            printf("Write error ... \n");
        }
        printf("Has already sent the data to the client");

    }
    close(clnt_sock);
    close(serv_sock);

    return 0;
}

3.2 Windows 客户端代码

// WindowsClient.c
 
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")  //加载 ws2_32.dll
 
#define BUF_SIZE 100
 
int main(){
    //初始化DLL
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
 
    //创建套接字
    SOCKET sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
 	printf("Try to connect to the server : 129.204.119.205 ...\n");
    //向服务器发起请求
    sockaddr_in sockAddr;
    memset(&sockAddr, 0, sizeof(sockAddr));  //每个字节都用0填充
    sockAddr.sin_family = PF_INET;
    sockAddr.sin_addr.s_addr = inet_addr("129.204.119.105");
    sockAddr.sin_port = htons(990);
    while (connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
		printf("Connection Error! Now re-try to get connected ... \n");		
	}
    //获取用户输入的字符串并发送给服务器
    while(1) {
		char bufSend[BUF_SIZE] = {0};
	    printf("Input a string: ");
	    scanf("%s", bufSend);
	    int sendLen = send(sock, bufSend, strlen(bufSend), 0);
	    if (sendLen < 0) {
			printf("Send Error, PLS Check your network ...\n");
			continue;
		}
		//接收服务器传回的数据
	    
		char bufRecv[BUF_SIZE] = {0};
	    int recLen = recv(sock, bufRecv, BUF_SIZE, 0);
	 	if (recLen < 0) {
		 	printf("Receive error, PLS check your network ...\n");
		 	continue;
		 }
	    //输出接收到的数据
	    printf("Message form server: %s\n", bufRecv);
 	}
    //关闭套接字
    closesocket(sock);
 
    //终止使用 DLL
    WSACleanup();
	printf("Message has been achieved, the Client now gonna cloese");
    system("pause");
    return 0;
}

3.3 Linux 客户端代码

有时间再补

 

 

 

 

 

  • 11
    点赞
  • 117
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值