Socket UDP远程传输图片

Socket UDP远程传输图片:以Window系统为客户端,Ubuntu系统为服务端进行图片传输。

Window:客户端代码

#include 
#include 
#include 
#include 
using namespace std;

#pragma comment(lib, "ws2_32.lib")
#define Port 50001 // 服务器端口地址
#define IP_ADDRESS "192.168.1.101" // 服务器ip地址

// 图片包格式
struct Package
{
	int length;
	char data[1024];
	int fin;
}picture;

int main(int argc, char* argv[])
{
    WSADATA ws;
    SOCKET clientSocket;
    struct sockaddr_in addr;
	int addr_len = sizeof(struct sockaddr_in);

    // 初始化Windows Socket
    if(WSAStartup(MAKEWORD(2, 2), &ws) != 0)
    {
        printf("Init Windows Socket Failed! Error: %d\n", GetLastError());
        return -1;
    }

    // 创建一个套接口
    clientSocket = socket(AF_INET, SOCK_DGRAM, 0);

    if(clientSocket == INVALID_SOCKET)
    {
        printf("Create Socket Failed! Error: %d\n", GetLastError());
        return -1;
    }

    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(IP_ADDRESS);
    addr.sin_port = htons(Port);
    memset(addr.sin_zero, 0X00, 8); // 函数通常为新申请的内存做初始化工作

	char img[20];
	cout << "Please input img to send: ";
	while(cin >> img)
	{
		// 打包发送图片
		FILE *fp;
		fp = fopen(img, "rb+");
		fseek(fp, 0, SEEK_END);
		int fend = ftell(fp);
		fseek(fp, 0, 0);
		int sendbytes, recvbytes;
		while(fend > 0)
		{
			memset(picture.data, 0, sizeof(picture.data));
			fread(picture.data, 1024, 1, fp);
			if(fend >= 1024) //还有剩余包未发送完
			{
				picture.length = 1024;
				picture.fin = 0;
			}
			else //最后一个包 
			{
				picture.length = fend;
				picture.fin = 1;
			}

			sendbytes = sendto(clientSocket, (char *)&picture, sizeof(struct Package), 0, (struct sockaddr*)&addr, addr_len);

			if(sendbytes == SOCKET_ERROR)
			{
				printf("Send Picture Failed! Error:%d\n", GetLastError());
				return -1;
			}
			else
			{
				fend -= 1024;  
			}
		}

		// 接收服务器回应
		char recvbuffer[256];
		recvbytes = recvfrom(clientSocket, recvbuffer, sizeof(recvbuffer), 0, (struct sockaddr*)&addr, &addr_len);
		cout << "Server: " << recvbuffer << endl;
		cout << "Please input img to send: ";
	}
	// 关闭socket
	closesocket(clientSocket);
	WSACleanup();
	return 0;
}

Ubuntu:服务端代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

#define PORT 50001

struct Package
{
    int length;
    char data[1024];
    int fin;
} picture;

//创建目录
void MakeDir(const string& filePath)
{
    DIR *dp;
	if((dp = opendir(filePath.c_str())) == NULL)
    {
        if(mkdir(filePath.c_str(), 0755) == -1)
            cout << filePath << " build failed!" << endl;
    }


    closedir(dp);
}
/*初始化接收图像,并获取当前时间,以此存储命名图片*/
void initImage(FILE* &fp)
{
    time_t t = time(0);
    char imgpath[128];
    strftime(imgpath, sizeof(imgpath), "%Y-%m-%d/", localtime(&t));
    MakeDir(imgpath);

    char imgname[64];
    strftime(imgname, sizeof(imgname), "%Y%m%d%H%M%S.jpg", localtime(&t));

    if(!(fp = fopen(strcat(imgpath, imgname), "wb+")))
    {
        printf("Open image Failed!\n");
        exit(1);
    }
}

int main(int argc, char* argv[])
{
    struct sockaddr_in addr;
    socklen_t sockfd, addr_len = sizeof(struct sockaddr_in);

    /* 建立socket,注意必须是SOCK_DGRAM */
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        perror ("socket failed!");
        exit(1);
    }

    /* 填写sockaddr_in 结构 */
    bzero(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    addr.sin_addr.s_addr = htonl(INADDR_ANY) ;

    /* 绑定socket */
    if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr))<0)
    {
        perror("connect failed!");
        exit(1);
    }

    while(1)
    {
        FILE* fp;
        bool flag = true;
        picture.fin = 0;

        while(!picture.fin)
        {
            memset(picture.data, 0, sizeof(picture.data));
            int recvbytes = recvfrom(sockfd, (char*)&picture, sizeof(struct Package),
                                     0, (struct sockaddr *)&addr, &addr_len);

            if(flag)
            {
                initImage(fp);
                flag = false;
            }

            if(recvbytes == 0)
                break;

            fwrite(picture.data, picture.length, 1, fp);
        }

        /* 显示client端的网络地址和收到的字符串消息 */
        //printf("Socket Server: IP: %s Connected!\n",  inet_ntoa(addr.sin_addr));
        cout << "Receive a picture. ip address: " << inet_ntoa(addr.sin_addr) << endl;

        char sendbuffer[256] = "Server Response";
        int sendbytes = sendto(sockfd, sendbuffer, sizeof(sendbuffer), 0, (struct sockaddr *)&addr, addr_len);

        fclose(fp); /*关闭fp,刷新缓冲区*/
    }
    close(sockfd);
    return 0;
}

注意事项:
1.分包发送,并定义包长度和包结尾,以便于服务器端的接收判断
2.服务器端接收图片时,要确保接收完整(最开始没有加上fclose(fp);刷新缓冲区导致图片接收不完整困扰了我很久,技术太渣了)
3.对于接收到的图片,获取当前时间的字符串格式将其保存
参考:
http://blog.csdn.net/yulinxx/article/details/51338214
http://velep.com/archives/934.html 

你可能感兴趣的:(Socket UDP远程传输图片)