socket 网络通信 ( windows + Linux )
参考:C++ socket 网络通信以下编程平台在VS2015上,实现服务器和客户端的通信服务器代码://server.cpp#include<iostream>#include<winsock.h>#pragma comment(lib,"ws2_32.lib")using namespace std;void initialization();int main(){//
·
参考:
C++ socket 网络通信等
socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。Socket就是该模式的一个实现, socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭).
说白了Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
交互流程:
TCP/IP通信中,主要是进行C/S交互。废话不多说,下面看看具体交互内容:
服务端:建立socket,申明自身的port和IP,并绑定到socket,使用listen监听,然后不断用accept去查看是否有连接。如果有,捕获socket,并通过recv获取消息的内容,通信完成后调用closeSocket关闭这个对应accept到的socket。如果不需要等待任何客户端连接,那么用closeSocket直接关闭自身的socket。
客户端:建立socket,通过端口号和地址确定目标服务器,使用Connect连接到服务器,send发送消息,等待处理,通信完成后调用closeSocket关闭socket。
windows平台(C++):
以下编程平台在VS2015上,新建两个不同的控制台应用程序,一个只有服务器代码,另一个只有客户端代码,同时运行,即可实现服务器和客户端的通信
服务器代码:
//server.cpp
#include<iostream>
#include<winsock.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
void initialization();
int main()
{
//定义长度变量
int send_len = 0;
int recv_len = 0;
int len = 0;
//定义发送缓冲区和接受缓冲区
char send_buf[100];
char recv_buf[100];
//定义服务端套接字,接受请求套接字
SOCKET s_server;
SOCKET s_accept;
//服务端地址客户端地址
SOCKADDR_IN server_addr;
SOCKADDR_IN accept_addr;
initialization();
//填充服务端信息
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(7777);
//创建套接字
s_server = socket(AF_INET, SOCK_STREAM, 0);
if (bind(s_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR)
{
cout << "套接字绑定失败!" << endl;
WSACleanup();
}
else
{
cout << "套接字绑定成功!" << endl;
}
//设置套接字为监听状态
if (listen(s_server, SOMAXCONN) < 0)
{
cout << "设置监听状态失败!" << endl;
WSACleanup();
}
else
{
cout << "设置监听状态成功!" << endl;
}
cout << "服务端正在监听连接,请稍候...." << endl;
//接受连接请求
len = sizeof(SOCKADDR);
s_accept = accept(s_server, (SOCKADDR *)&accept_addr, &len);
if (s_accept == SOCKET_ERROR)
{
cout << "连接失败!" << endl;
WSACleanup();
return 0;
}
cout << "连接建立,准备接受数据" << endl;
//接收数据
while (1)
{
recv_len = recv(s_accept, recv_buf, 100, 0);
if (recv_len < 0)
{
cout << "接受失败!" << endl;
break;
}
else
{
cout << "客户端信息:" << recv_buf << endl;
}
cout << "请输入回复信息:";
cin >> send_buf;
send_len = send(s_accept, send_buf, 100, 0);
if (send_len < 0)
{
cout << "发送失败!" << endl;
break;
}
}
//关闭套接字
closesocket(s_server);
closesocket(s_accept);
//释放DLL资源
WSACleanup();
return 0;
}
void initialization()
{
//初始化套接字库
WORD w_req = MAKEWORD(2, 2);//版本号
WSADATA wsadata;
int err;
err = WSAStartup(w_req, &wsadata);
if (err != 0)
{
cout << "初始化套接字库失败!" << endl;
}
else
{
cout << "初始化套接字库成功!" << endl;
}
//检测版本号
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2)
{
cout << "套接字库版本号不符!" << endl;
WSACleanup();
}
else
{
cout << "套接字库版本正确!" << endl;
}
}
客户端代码:
//client.cpp
#include<iostream>
#include<winsock.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
void initialization();
int main()
{
//定义长度变量
int send_len = 0;
int recv_len = 0;
//定义发送缓冲区和接受缓冲区
char send_buf[100];
char recv_buf[100];
//定义服务端套接字,接受请求套接字
SOCKET s_server;
//服务端地址客户端地址
SOCKADDR_IN server_addr;
initialization();
//填充服务端信息
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons(7777);
//创建套接字
s_server = socket(AF_INET, SOCK_STREAM, 0);
if (connect(s_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR)
{
cout << "服务器连接失败!" << endl;
WSACleanup();
}
else
{
cout << "服务器连接成功!" << endl;
}
//发送,接收数据
while (1)
{
cout << "请输入发送信息:";
cin >> send_buf;
send_len = send(s_server, send_buf, 100, 0);
if (send_len < 0)
{
cout << "发送失败!" << endl;
break;
}
recv_len = recv(s_server, recv_buf, 100, 0);
if (recv_len < 0)
{
cout << "接受失败!" << endl;
break;
}
else
{
cout << "服务端信息:" << recv_buf << endl;
}
}
//关闭套接字
closesocket(s_server);
//释放DLL资源
WSACleanup();
return 0;
}
void initialization()
{
//初始化套接字库
WORD w_req = MAKEWORD(2, 2);//版本号
WSADATA wsadata;
int err;
err = WSAStartup(w_req, &wsadata);
if (err != 0)
{
cout << "初始化套接字库失败!" << endl;
}
else
{
cout << "初始化套接字库成功!" << endl;
}
//检测版本号
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2)
{
cout << "套接字库版本号不符!" << endl;
WSACleanup();
}
else
{
cout << "套接字库版本正确!" << endl;
}
}
现象:
Linux平台(C代码):
服务器代码:
/* File Name: server.c */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include <unistd.h>
#define DEFAULT_PORT 8000
#define MAXLINE 4096
int main(int argc, char** argv)
{
int socket_fd, connect_fd;
struct sockaddr_in servaddr;
char sendline[4096];
char buff[4096];
int n;
//初始化Socket
if( (socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
{
printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
//初始化
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址设置成INADDR_ANY,让系统自动获取本机的IP地址。
servaddr.sin_port = htons(DEFAULT_PORT); //设置的端口为DEFAULT_PORT
//将本地地址绑定到所创建的套接字上
if( bind(socket_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1)
{
printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
//开始监听是否有客户端连接
if( listen(socket_fd, 10) == -1)
{
printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
printf("waiting for client's request...\n");
//多个客户端与服务器建立连接,发送消息
/*
while(1)
{
//阻塞直到有客户端连接,不然多浪费CPU资源。
if((connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL)) == -1)
{
printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
continue;
}
//接受客户端传过来的数据
n = recv(connect_fd, buff, MAXLINE, 0);
buff[n] = '\0';
printf("recv msg from client: %s\n", buff);
}
*/
//单个客户端与服务器建立连接,发送消息并回复消息,多次通信
if((connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL)) == -1) //阻塞直到有客户端连接,不然多浪费CPU资源。
{
printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
}
else
{
printf("client connected!\n");
}
while(1)
{
//接受客户端传过来的数据
n = recv(connect_fd, buff, MAXLINE, 0);
buff[n] = '\0';
printf("recv msg from client: %s", buff);
//给客户端发送消息
printf("send msg to client:");
fgets(sendline, 4096, stdin);
if( send(connect_fd, sendline, strlen(sendline), 0) < 0)
{
printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
exit(0);
}
}
close(connect_fd);
close(socket_fd);
}
客户端代码:
/* File Name: client.c */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include <unistd.h>
#define MAXLINE 4096
int main(int argc, char** argv)
{
int sockfd, n, rec_len;
char recvline[4096], sendline[4096];
char buf[MAXLINE];
struct sockaddr_in servaddr;
if( argc != 2)
{
printf("usage: ./client <ipaddress>\n");
exit(0);
}
//初始化socket
if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);
exit(0);
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(8000);
//将点分文本的IP地址转换为二进制网络字节序的IP地址
if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
{
printf("inet_pton error for %s\n",argv[1]);
exit(0);
}
//连接服务端
if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
{
printf("connect error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
else
{
printf("connect server success!\n");
}
while(1)
{
printf("send msg to server:");
fgets(sendline, 4096, stdin);
if( send(sockfd, sendline, strlen(sendline), 0) < 0)
{
printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
exit(0);
}
if((rec_len = recv(sockfd, buf, MAXLINE,0)) == -1)
{
perror("recv error");
exit(1);
}
else
{
buf[rec_len] = '\0';
printf("recv msg from server:%s",buf);
}
}
close(sockfd);
exit(0);
}
Makefile:
ifeq ($(DEBUG),Enable)
CPPFLAGS = -D_DEBUG -g -Wall
else
CPPFLAGS = -s
endif
INCS=-I./include
LIBS=./lib
OUTDIR=./
TARGET_CLIENT=client
TARGET_SERVER=server
exe:
gcc $(CPPFLAGS) $(INCS) client.c -o $(OUTDIR)/$(TARGET_CLIENT)
gcc $(CPPFLAGS) $(INCS) server.c -o $(OUTDIR)/$(TARGET_SERVER)
all: exe
clean:
rm $(OUTDIR)/$(TARGET)
现象:
首先启动服务器,等待客户端连接
然后客户端连接上来,准备发送信息
这时服务端已经收到了客户端连接
然后客户端发信息给服务端
服务端接收到信息
最终实现互相通信,当然这只是与一个客户端通信,放开服务端代码中的注释部分,可以实现多个客户端与服务器建立连接。
更多推荐
已为社区贡献3条内容
所有评论(0)