当前位置 博文首页 > 缘分锝天空的博客:嵌入式课程设计:socket通信模拟服务器客户端

    缘分锝天空的博客:嵌入式课程设计:socket通信模拟服务器客户端

    作者:[db:作者] 时间:2021-07-21 09:48

    ????????本次课程设计时间大概是两天半,磕磕碰碰,一路上遇到了很多的问题,也不断的查资料,想办法解决各种拦路的BUG,最后做出来的效果自己还是挺满意的,能够实现多台电脑之间模拟服务端,客户端,进行文件传送。下面做一下整理(附程序和运行效果截图)

    本次课程设计完成任务如下:

    (1)学习TCP/IP网络基本知识,学习socket通信基本知识,设计基于Socket的网络通信程序,在LINUX 系统与WINDOWS系统之间进行通信,使用C++语言实现。

    (2)在Socket服务端,能够读出一副图像数据,经过网络通信,自己设计协议,将这副图片发送到客户端,客户端接收到这副图片后,将其显示在屏幕上。

    直接看程序吧,有挺详细的注释->

    服务端程序:

    #include<iostream>
    //#include<winsock.h>
    #include <winsock2.h>
    #include<stdio.h>
    #include<stdlib.h>
    #pragma comment(lib,"ws2_32.lib")
    using namespace std;
    void initialization();
    #define BUF_SIZE 1024
    SOCKET s_accept;
    SOCKADDR_IN accept_addr;
    void sendFile() {
    	cout << "输入待传送的文件名:";
    	char filename1[100];
    	cin >> filename1;
    	//检查文件是否存在
    	const char *filename = filename1;
    #pragma warning(suppress : 4996)
    	FILE *fp = fopen(filename, "rb");
    	if (fp == NULL)
    	{
    		printf("不能打开文件,按任何键退出!");
    		system("pause");
    		
    	}
    	else
    	{
    		cout << "文件准备就绪" << endl;
    	}
    	//循环发送数据,直到文件结尾
    	char buffer[BUF_SIZE] = { 0 };//缓冲区
    	int nCount;
    	while ((nCount = fread(buffer, 1, BUF_SIZE, fp)) > 0)
    	{
    		send(s_accept, buffer, nCount, 0);
    	}
    	shutdown(s_accept, SD_SEND);文件读取完毕,断开输出流,向客户端发送FIN包,注意加头文件#include <winsock2.h>,不然报错
    	recv(s_accept, buffer, BUF_SIZE, 0);//阻塞,等待客户端接收完毕
    	//关闭文件
    	fclose(fp);
    }
    void listen1(SOCKET s_server,int len, SOCKADDR_IN accept_addr) {
    	//设置套接字为监听状态
    	if (listen(s_server, SOMAXCONN) < 0) {
    		cout << "设置监听状态失败!" << endl;
    		WSACleanup();
    	}
    	else {
    		cout << "设置监听状态成功!" << endl;
    	}
    	cout << "服务端正在监听连接,请稍候...." << endl;
    	cout << "-------------------------------------" << endl;
    	//接受连接请求
    	len = sizeof(SOCKADDR);
    	s_accept = accept(s_server, (SOCKADDR*)&accept_addr, &len);
    	if (s_accept == SOCKET_ERROR) {
    		cout << "连接失败!" << endl;
    		WSACleanup();
    	}
    	cout << "连接就绪~" << endl;
    }
    int main() {
    	//定义长度变量
    	int len = 0;
    	//定义服务端套接字,接受请求套接字
    	SOCKET s_server;
    	//服务端地址客户端地址
    	SOCKADDR_IN server_addr;
    	initialization();
    	//填充服务端信息
    	server_addr.sin_family = AF_INET;
    	server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    	//设置端口号
    	server_addr.sin_port = htons(1234);
    	//创建套接字
    	s_server = socket(AF_INET, SOCK_STREAM, 0);
    	//绑定套接字到一个IP地址和一个端口上
    	if (bind(s_server, (SOCKADDR*)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
    		cout << "-----------------------------" << endl;
    		cout << "套接字绑定失败!" << endl;
    		WSACleanup();
    	}
    	else {
    		cout << "套接字绑定成功!" << endl;
    	}
    	//监听
    	listen1(s_server, len, accept_addr);
    	//发送文件
    	while (true)
    	{
    		sendFile();
    	}
    	//关闭套接字
    	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 << "  计181李延胜" << endl;
    		cout << "--------------------------------------" << endl;
    		cout << "初始化套接字库成功!" << endl;
    	}
    }
    

    客户端程序:

    #include<iostream>
    #include<winsock.h>
    #pragma comment(lib,"ws2_32.lib")
    using namespace std;
    #define BUF_SIZE 1024
    void initialization();
    int main() {
    	//定义服务端套接字,接受请求套接字
    	SOCKET s_server;
    	//服务端地址客户端地址
    	SOCKADDR_IN server_addr;
    	initialization();
    	//填充服务端信息
    	server_addr.sin_family = AF_INET;
    	//获取IP
    	cout << "-------------------------" << endl;
    	cout << "输入服务器的IP:";
    	//定义保存输入IP的字符数组
    	char Service_ip[15];
    	//遇到空格或者回车结束输入
    	cin >> Service_ip;
    	server_addr.sin_addr.S_un.S_addr = inet_addr(Service_ip);
    	//server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    	server_addr.sin_port = htons(1234);
    	//创建套接字
    	s_server = socket(AF_INET, SOCK_STREAM, 0);
    	if (connect(s_server, (SOCKADDR*)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
    		cout << "服务器连接失败!" << endl;
    		WSACleanup();
    		WSACleanup();
    	}
    	else {
    		cout << "服务器连接成功!" << endl;
    	}
    	while (1)
    	{
    		//输入文件名,看文件能否创建成功
    		char filename[100] = { 0 };
    		cout << "请输入要保存的文件:";
    		cin >> filename;
    		//以二进制创建文件
    #pragma warning(suppress : 4996)
    		FILE *fp = fopen(filename, "wb");//以只写方式打开或新建一个二进制文件,只允许写数据
    		//循环接受
    		char buffer[BUF_SIZE] = { 0 };//文件保存缓冲区
    		int nCount = 0;
    		while ((nCount = recv(s_server, buffer, BUF_SIZE, 0)) > 0)//recv(对应的套接字,保存数据的地方,保存区的大小,第四个参数一般设置为 0
    		{
    			fwrite(buffer, nCount, 1, fp);//buffer输出数据的地址,nCount要输入内容的字节数,1位写入nCount字节的数据项的个数,fp为目标文件
    		}
    		if (fp == NULL)
    		{
    			cout << "接收文件失败!";
    			system("pause");
    			exit(0);
    		}
    		if (fp != NULL) {
    			cout << "文件接收成功!" << endl;
    		}
    		//打开并显示图片
    		ShellExecute(NULL,"open", filename, NULL, NULL, SW_SHOWNORMAL);
    		system("pause");
    		fclose(fp);
    	}
    	//关闭套接字
    	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 (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) {
    		cout << "套接字库版本号不符!" << endl;
    		WSACleanup();
    	}
    	else {
    		cout << "计181李延胜" << endl;
    		cout << "套接字库版本正确!" << endl;
    	}
    	
    }
    

    ?程序执行效果

    分别运行服务端和客户端,本机测试IP地址用127.0.0.1,局域网的话IP自己查IPv4对应的IP号(这里用本机回环测试演示)

    在客户端输入IP,然后回车可以看到连接是否成功

    ?然后在服务端输入要传送的文件的路径:(这里演示传送一个视频,发送图片的方式也同理)

    ?

    ?在客户端也输入要保存服务端传送过来文件的地址,保存在哪里可以自己定义,文件名也可以自己定义,但是文件格式一定要跟服务器传过来的文件的文件格式一致,即文件后缀名要一样

    ?文件传送成功后,程序会自动调用计算机的默认应用打开文件,即你是传送的文件,那么你收到文件后,系统会调用计算机的视频播放软件打开,如果是图片,那么就会用图片查看器打开,其他文件格式也同理

    ?打开刚刚保存文件的路径,可以看到我们的文件传送过来了,两个文件大小一致

    ?

    不同计算机连接同一个局域网也能实现文件传送呢,感兴趣的伙伴可以试一下哦!!

    程序不足之处:一次运行只能传输一次文件,然后程序就结束退出了,需要再一次传送文件还得再重新先打开服务端然后打开客户端连接,?这个可以考虑把发送接收文件的代码块放到一个循环里,我今天简单尝试了一下,没有成功,时间问题,就没来得及继续完善这个不足了,感兴趣的伙伴可以把上面程序修改修改试试

    以上程序的注释是个人对程序的一些理解,可能存在有错误的地方,欢迎大家留言指正!!

    创作不易,喜欢的伙伴三连支持一下哦!

    ?

    cs