以下代码测试环境为:
服务器:CentOS 7.5 64位
客户端1:Ubuntu 16.04 LTS
客户端2:Win10 Server(服务器主机)
Socket实现Linux服务器和windows客户端&linux客户端的通信
1.实现Linux服务器向windows客户端和Linux客户端发送数据
2.实现Linux服务器和Windows客户端&Linux客户端双向发送与接收的“回声服务器”
3. 实现Linux服务端和windows客户端&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 客户端代码
有时间再补