设计要求:
通过基于socket技术的多机通信程序,实现短消息传递、文件传输。
操作流程:
服务器端编程的步骤:
1:加载套接字库,创建套接字(WSAStartup()/socket());
2:绑定套接字到一个IP地址和一个端口上(bind());
3:将套接字设置为监听模式等待连接请求(listen());
4:请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept());
5:用返回的套接字和客户端进行通信(send()/recv());
6:返回,等待另一连接请求;
7:关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup())。
客户端编程的步骤:
1:加载套接字库,创建套接字(WSAStartup()/socket());
2:向服务器发出连接请求(connect());
3:和服务器端进行通信(send()/recv());
4:关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup())。
服务端:
#pragma warning(disable : 4996)
#include<iostream>
#include<Winsock2.h>
#include<fstream>
#include<string>
#pragma comment(lib, "WS2_32.lib")
using namespace std;
int server(SOCKET socket_connect)
{
cout << "一个用户建立连接" << endl;
cout << "m:进入发送信息模式" << endl;
cout << "f:进入发送文件模式" << endl;
cout << "g:进入接收模式" << endl;
int judge = 1;
while (judge)
{
char c;
cin >> c;
ifstream ifile;
char send_message[266];
char receive_message[266] ;
receive_message[265] = '\0';
string s;
switch (c)
{
case 'm'://发消息
strcpy(send_message, "#mID:00 ");
cout << "请输入发送的信息,限256个字符" << endl;
cin >> send_message + 9;
send(socket_connect, send_message, sizeof(send_message), 0);
break;
case 'f'://发文件
ifile.open("server_send_data.txt", ios::in); //文件要求1行不超过256个字符
while (getline(ifile, s))
send(socket_connect, strcat(strcpy(send_message, "#fID:00 "), s.c_str()), sizeof(send_message), 0);
ifile.close();
cout << "文件已发出,将文件名为:server_send_data.txt.txt的内容发送" << endl;
break;
case 'g'://接收
recv(socket_connect, receive_message, sizeof(receive_message), 0);
if (receive_message[0] == '$')
{
closesocket(socket_connect);
judge = 0;
cout << "用户断开连接," << receive_message + 2 << endl;
}
if (receive_message[1] == 'm')
{
cout << "收到一条新消息:" << receive_message + 2 << endl;
send(socket_connect, "#!服务器已收到消息", sizeof("#!服务器已收到消息"), 0);
}
if (receive_message[1] == '!')
{
cout << "收到客户端反馈:" << receive_message + 2 << endl;
}
if (receive_message[1] == 'f')
{
ofstream ofile;
ofile.open("server_get_data.txt", ios::app);
ofile << receive_message + 2 << endl;
ofile.close();
cout << "收到文件,已写入:server_get_data.txt" << endl;
send(socket_connect, "#!服务器已收到文件", sizeof("#!服务器已收到文件"), 0);
}
break;
default:
cout << "输入命令有误,请重新输入" << endl;
}
}
return 0;
}
int main()
{
cout << "服务端启动" << endl;
//加载套接字库
WSADATA wsaData;
int result = WSAStartup(MAKEWORD(1, 1), &wsaData);
if (result != 0)
{
cout << "socket库绑定失败,程序终止。" << endl;
return -1;
}
if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
{
WSACleanup();
cout << "Socket获取的版本与socket需要的版本不符,程序终止。" << endl;
return -1;
}
//创建套接字 基于IPv4的地址+端口 ,TCP/IP协议
SOCKET socket_service = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
SOCKADDR_IN socket_service_address;
socket_service_address.sin_family = AF_INET;
socket_service_address.sin_port = htons(13000);//字节序转换
//将一个点分十进制的IP转换成一个长整数型数
socket_service_address.sin_addr.s_addr = htonl(INADDR_ANY);
// inet_addr("127.0.0.1"); 两种选择:1.设置为htonl(INADDR_ANY);INADDR_ANY为本机所有IP,用于多网卡主机 2.设置为具体的IP。
bind(socket_service, (SOCKADDR*)&socket_service_address, sizeof(SOCKADDR_IN));
listen(socket_service,2);
//以$开头代表命令 以#开头代表信息 内容中出现 $ # \ 符号时前面需加\号。
SOCKADDR_IN socket_client_address;
int len = sizeof(SOCKADDR);
while (1)
{
SOCKET socket_connect = accept(socket_service, (SOCKADDR*)&socket_client_address, &len);
server(socket_connect);
}
WSACleanup();
return 0;
}
客户端:
#include<iostream>
#include<fstream>
#include <conio.h>
#include<Winsock2.h>
#include<string>
#pragma comment(lib, "WS2_32.lib")
using namespace std;
/*
1.加载套接字库
2.创建套接字
3.向服务器发出连接请求
*/
int main()
{
cout << "客户端启动" << endl;
//加载套接字库
WSADATA wsaData;
int result= WSAStartup(MAKEWORD(1, 1), &wsaData);
if (result != 0)
{
cout<< "socket库绑定失败,程序终止。"<<endl;
return -1;
}
if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
{
WSACleanup();
cout<<"Socket获取的版本与socket需要的版本不符,程序终止。"<<endl;
return -1;
}
//创建套接字 基于IPv4的地址+端口 ,TCP/IP协议
int socket_client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//向服务器发出连接请求
SOCKADDR_IN address;
address.sin_family=AF_INET;
address.sin_port=htons(13000);//字节序转换
//将一个点分十进制的IP转换成一个长整数型数
address.sin_addr.s_addr=inet_addr("127.0.0.1");
int i=connect(socket_client,(SOCKADDR*)&address,sizeof(SOCKADDR_IN));
if(i!=0)
cout<<"连接失败"<<endl;
else
{
cout << "套接字初始化成功,可以开始通信。" << endl;
cout << "m:进入发送信息模式" << endl;
cout << "f:进入发送文件模式" << endl;
cout << "g:进入接收模式" << endl;
cout << "q:断开与服务器连接" << endl;
int judge = 1;
while (judge)
{
char c;
cin >> c;
ifstream ifile;
ofstream ofile;
char send_message[266];
char receive_message[266];
receive_message[265] = '\0';
string s;
switch (c)
{
case 'm'://发消息
strcpy(send_message, "#mID:01 ");
cout << "请输入发送的信息,限256个字符" << endl;
cin >> send_message + 9;
send(socket_client, send_message, sizeof(send_message), 0);
break;
case 'f'://发文件
ifile.open("client_send_data.txt", ios::in); //文件要求1行不超过256个字符
while (getline(ifile, s))
send(socket_client, strcat(strcpy(send_message, "#fID:01 "), s.c_str()), sizeof(send_message), 0);
ifile.close();
cout << "文件已发出,将文件名为:client_send_data.txt的内容发送" << endl;
break;
case 'g'://接收
recv(socket_client, receive_message, sizeof(receive_message), 0);
if (receive_message[1] == 'm')
{
cout << "收到一条新消息:" << receive_message + 2 << endl;
send(socket_client, "#!客户端已收到消息", sizeof("#!客户端已收到消息"), 0);
}
if (receive_message[1] == '!')
{
cout << "收到服务端反馈:" << receive_message + 2 << endl;
}
if (receive_message[1] == 'f')
{
ofile.open("client_get_data.txt", ios::app);
ofile << receive_message + 2 << endl;
cout << "收到文件,已写入:client_get_data.txt" << endl;
send(socket_client, "#!客户端已收到文件", sizeof("#!客户端已收到文件"), 0);
ofile.close();
}
break;
case 'q'://断开连接
strcpy(send_message, "#qID:01");
send(socket_client, send_message, sizeof(send_message), 0);
closesocket(socket_client);
judge = 0;
break;
default:
cout << "输入命令有误,请重新输入" << endl;
}
}
}
WSACleanup();
return 0;
}