send file using winsock c++

I am trying to send a text file from client to server and server should return that text file back to client after reading and updating the contents of the file. Then client should read the file, then select the options provided in the text file to connect to only one of those server using winsock c++?So far below is what I have done in c linux. Can anyone help rewrite it with winsock apis c++?

/*client.c*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <signal.h>
#include <ctype.h>          
#include <arpa/inet.h>
#include <netdb.h>

#define PORT 30000
#define LENGTH 512 


void error(const char *msg)
{
	perror(msg);
	exit(1);
}

int main(int argc, char *argv[])
{
	/* Variable Definition */
	int sockfd; 
	int nsockfd;
	char revbuf[LENGTH]; 
	struct sockaddr_in remote_addr;

	/* Get the Socket file descriptor */
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		fprintf(stderr, "ERROR: Failed to obtain Socket Descriptor! (errno = %d)\n",errno);
		exit(1);
	}

	/* Fill the socket address struct */
	remote_addr.sin_family = AF_INET; 
	remote_addr.sin_port = htons(PORT); 
	inet_pton(AF_INET, "127.0.0.1", &remote_addr.sin_addr); 
	bzero(&(remote_addr.sin_zero), 8);

	/* Try to connect the remote */
	if (connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1)
	{
		fprintf(stderr, "ERROR: Failed to connect to the host! (errno = %d)\n",errno);
		exit(1);
	}
	else 
		printf("[Client] Connected to server at port %d...ok!\n", PORT);

	/* Send File to Server */
	//if(!fork())
	//{
		char* fs_name = "/home/jimmy/Desktop/test.txt";
		char sdbuf[LENGTH]; 
		printf("[Client] Sending %s to the Server... ", fs_name);
		FILE *fs = fopen(fs_name, "r");
		if(fs == NULL)
		{
			printf("ERROR: File %s not found.\n", fs_name);
			exit(1);
		}

		bzero(sdbuf, LENGTH); 
		int fs_block_sz; 
		while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs)) > 0)
		{
		    if(send(sockfd, sdbuf, fs_block_sz, 0) < 0)
		    {
		        fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno);
		        break;
		    }
		    bzero(sdbuf, LENGTH);
		}
		printf("Ok File %s from Client was Sent!\n", fs_name);
	//}

	/* Receive File from Server */
	printf("[Client] Receiveing file from Server and saving it as final.txt...");
	char* fr_name = "/home/jimmy/Desktop/test/final.txt";
	FILE *fr = fopen(fr_name, "a");
	if(fr == NULL)
		printf("File %s Cannot be opened.\n", fr_name);
	else
	{
		bzero(revbuf, LENGTH); 
		int fr_block_sz = 0;
	    while((fr_block_sz = recv(sockfd, revbuf, LENGTH, 0)) > 0)
	    {
			int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);
	        if(write_sz < fr_block_sz)
			{
	            error("File write failed.\n");
	        }
			bzero(revbuf, LENGTH);
			if (fr_block_sz == 0 || fr_block_sz != 512) 
			{
				break;
			}
		}
		if(fr_block_sz < 0)
        {
			if (errno == EAGAIN)
			{
				printf("recv() timed out.\n");
			}
			else
			{
				fprintf(stderr, "recv() failed due to errno = %d\n", errno);
			}
		}
	    printf("Ok received from server!\n");
	    fclose(fr);
	}
	close (sockfd);
	printf("[Client] Connection lost.\n");
	return (0);
}



Below is the /*server.c*/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <signal.h>
#include <ctype.h>          
#include <arpa/inet.h>
#include <netdb.h>

#define PORT 30000 
#define BACKLOG 5
#define LENGTH 512 

void error(const char *msg)
{
	perror(msg);
	exit(1);
}

int main ()
{
	/* Defining Variables */
	int sockfd; 
	int nsockfd; 
	int num;
	int sin_size; 
	struct sockaddr_in addr_local; /* client addr */
	struct sockaddr_in addr_remote; /* server addr */
	char revbuf[LENGTH]; // Receiver buffer

	/* Get the Socket file descriptor */
	if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
	{
		fprintf(stderr, "ERROR: Failed to obtain Socket Descriptor. (errno = %d)\n", errno);
		exit(1);
	}
	else 
		printf("[Server] Obtaining socket descriptor successfully.\n");

	/* Fill the client socket address struct */
	addr_local.sin_family = AF_INET; // Protocol Family
	addr_local.sin_port = htons(PORT); // Port number
	addr_local.sin_addr.s_addr = INADDR_ANY; // AutoFill local address
	bzero(&(addr_local.sin_zero), 8); // Flush the rest of struct

	/* Bind a special Port */
	if( bind(sockfd, (struct sockaddr*)&addr_local, sizeof(struct sockaddr)) == -1 )
	{
		fprintf(stderr, "ERROR: Failed to bind Port. (errno = %d)\n", errno);
		exit(1);
	}
	else 
		printf("[Server] Binded tcp port %d in addr 127.0.0.1 sucessfully.\n",PORT);

	/* Listen remote connect/calling */
	if(listen(sockfd,BACKLOG) == -1)
	{
		fprintf(stderr, "ERROR: Failed to listen Port. (errno = %d)\n", errno);
		exit(1);
	}
	else
		printf ("[Server] Listening the port %d successfully.\n", PORT);

	int success = 0;
	while(success == 0)
	{
		sin_size = sizeof(struct sockaddr_in);

		/* Wait a connection, and obtain a new socket file despriptor for single connection */
		if ((nsockfd = accept(sockfd, (struct sockaddr *)&addr_remote, &sin_size)) == -1) 
		{
		    fprintf(stderr, "ERROR: Obtaining new Socket Despcritor. (errno = %d)\n", errno);
			exit(1);
		}
		else 
			printf("[Server] Server has got connected from %s.\n", inet_ntoa(addr_remote.sin_addr));

		/*Receive File from Client */
		char* fr_name = "/home/jimmy/Desktop/receive.txt";
		FILE *fr = fopen(fr_name, "a");
		if(fr == NULL)
			printf("File %s Cannot be opened file on server.\n", fr_name);
		else
		{
			bzero(revbuf, LENGTH); 
			int fr_block_sz = 0;
			while((fr_block_sz = recv(nsockfd, revbuf, LENGTH, 0)) > 0) 
			{
			    int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);
				if(write_sz < fr_block_sz)
			    {
			        error("File write failed on server.\n");
			    }
				bzero(revbuf, LENGTH);
				if (fr_block_sz == 0 || fr_block_sz != 512) 
				{
					break;
				}
			}
			if(fr_block_sz < 0)
		    {
		        if (errno == EAGAIN)
	        	{
	                printf("recv() timed out.\n");
	            }
	            else
	            {
	                fprintf(stderr, "recv() failed due to errno = %d\n", errno);
					exit(1);
	            }
        	}
			printf("Ok received from client!\n");
			fclose(fr); 
		}

		/* Call the Script */
		system("cd ; chmod +x script.sh ; ./script.sh");

		/* Send File to Client */
		//if(!fork())
		//{
		    char* fs_name = "/home/jimmy/Desktop/output.txt";
		    char sdbuf[LENGTH]; // Send buffer
		    printf("[Server] Sending %s to the Client...", fs_name);
		    FILE *fs = fopen(fs_name, "r");
		    if(fs == NULL)
		    {
		        fprintf(stderr, "ERROR: File %s not found on server. (errno = %d)\n", fs_name, errno);
				exit(1);
		    }

		    bzero(sdbuf, LENGTH); 
		    int fs_block_sz; 
		    while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs))>0)
		    {
		        if(send(nsockfd, sdbuf, fs_block_sz, 0) < 0)
		        {
		            fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno);
		            exit(1);
		        }
		        bzero(sdbuf, LENGTH);
		    }
		    printf("Ok sent to client!\n");
		    success = 1;
		    close(nsockfd);
		    printf("[Server] Connection with Client closed. Server will wait now...\n");
		    while(waitpid(-1, NULL, WNOHANG) > 0);
		//}
	}
}
The shell script that the server runs, what does that do?

As you've removed fork(), you should also remove that while(waitpid() loop.

EDIT:
1. Also, you seem to have C programs. Are you using C or C++?
2. server initialization of addr_local is wrong. How do you know write 8 bytes?
3. The call to bind() is incorrect, the size is wrong. I'm surprised it works. Does it?

I am trying to send a text file from client to server and server should return that text file back to client after reading and updating the contents of the file.
The server reads the client's request and writes it to a file called receive.txt, it then sends the content of output.txt.

Before we fix this, what should the server do with what it receives from the client? That "update" you mention, what exactly is that? What should the client do with it?
Last edited on
The client should get all info about the servers and those details must be updated in the text file which is resend back to the client, based on which client can select one of the options in the text file and reconnect to one server at a time. This code doesn't work and Im trying to fix,need to do it in C++ winsock, though the sample code provided is in C.
Ok, I'll help to get it working.

The idea is to fix the existing posix version, then port that to Windows. We'll use C++ as that's more portable; threads and sync objects are different in Windows and POSIX, but unified in the C++ standard (template) library.
I don't quite understand this shunting some file backwards and forwards between clients and servers. In general you haven't answered my questions at all, and those you do, not well.

This is what I've done:
1. I've made the client send commands to the server and the server send a reply to each.
2. The Client starts by sending HELLO and ends by sending BYE, or just terminating.
3. The server spawns a thread to handle each client conversation.
4. You can specify the server port on the command-line.
5. You can specify the ip and port for the client command-line.
6. The above two allow you run multiple clients and severs at the same time.
7. The code is as simple as possible, based on our passed interactions, except the random number used in srand() is necessarily obtuse.
8. I hope you can rethink how you want your servers and clients to communicate, based on this.
9. Feel free to change it and adapt it to your purpose, but don't hold me responsible if it breaks (2 clause BSD licence)
10. Runs on Windows (vs2019) and all Posix.
11. There's a git repo for this: git@bitbucket.org:kbw/general-279167.git
12. Good luck.

common.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#pragma once

#include <cstdio>
#include <cstdlib>
#include <cstdint>

constexpr std::uint16_t PORT = 30000;
constexpr int BACKLOG = 5;
constexpr std::size_t LENGTH = 512;

#ifdef _WIN32
	typedef int ssize_t;
	inline void sleep(int seconds) {
		Sleep(seconds * 1000);
	}
#else
	typedef int SOCKET;
	constexpr int SOCKET_ERROR = -1;
#endif

inline void fatal(const char *msg) {
	std::perror(msg);
	std::exit(1);
}


client.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#ifdef _WIN32
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment (lib, "Ws2_32.lib")
#else
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif

#include "../common.hpp"

#include <cstdio>
#include <cstring>
#include <string>

int main(int argc, char *argv[]) {
#ifdef _WIN32
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2,2), &wsaData);
#endif
	int rc;
	const std::string server = (argc > 1) ? argv[1] : "127.0.0.1";
	const std::uint16_t port = (argc > 2) ? static_cast<std::uint16_t>(std::atoi(argv[2])) : PORT;

	// Get the Socket file descriptor
	SOCKET sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sock == SOCKET_ERROR)
		fatal("socket()");

	// server address
	struct sockaddr_in remote_addr;
	std::memset(&remote_addr, 0, sizeof(remote_addr));
	remote_addr.sin_family = AF_INET; 
	remote_addr.sin_port = htons(port); 
	inet_pton(AF_INET, server.c_str(), &remote_addr.sin_addr); 

	// connect to server
	rc = connect(sock, (struct sockaddr*)&remote_addr, sizeof(remote_addr));
	if (rc == SOCKET_ERROR)
		fatal("connect()");
	printf("[Client] Connected to %s:%d\n", server.c_str(), port);

	char buffer[LENGTH];
	ssize_t nbytes;
	int len;

	// send HELLO
	len = std::snprintf(buffer, sizeof(buffer), "HELLO: %s:%d", server.c_str(), port);
	nbytes = ::send(sock, buffer, len, 0);
	if (nbytes != len)
		fatal("send(HELLO)");

	// read HELLO reply
	nbytes = ::recv(sock, buffer, LENGTH, 0);
	if (nbytes <= 0)
		fatal("recv HELLO reply");

	// send BYE
	len = std::snprintf(buffer, sizeof(buffer), "BYE: %s:%d", server.c_str(), port);
	nbytes = ::send(sock, buffer, len, 0);
	if (nbytes != len)
		fatal("send(BYE)");

	// read BYE reply
	nbytes = ::recv(sock, buffer, LENGTH, 0);
	if (nbytes <= 0)
		fatal("recv BYE reply");

	printf("[Client] Done\n");
#ifdef _WIN32
	closesocket(sock);
#else
	close(sock);
#endif
}


server.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#ifdef _WIN32
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment (lib, "Ws2_32.lib")
#else
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif

#include "../common.hpp"

#include <chrono>
#include <cstring>
#include <sstream>
#include <string>
#include <thread>

void handle_client(SOCKET client);

int main(int argc, char* argv[]) {
#ifdef _WIN32
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2,2), &wsaData);
#endif
	std::srand(
		std::chrono::time_point_cast<std::chrono::microseconds>( std::chrono::steady_clock::now() )
			.time_since_epoch()
			.count() % RAND_MAX);
	int rc;
	const std::uint16_t port = (argc > 2) ? static_cast<std::uint16_t>(std::atoi(argv[1])) : PORT;

	/* Create socket */
	SOCKET sock = socket(PF_INET, SOCK_STREAM, IPPROTO_IP);
	if (sock == SOCKET_ERROR)
		fatal("socket()");
	std::printf("[Server] created socket.\n");

	/* Fill the client socket address struct */
	struct sockaddr_in addr_local;
	std::memset(&addr_local, 0, sizeof(addr_local)); // Flush the rest of struct
	addr_local.sin_family = AF_INET; // Protocol Family
	addr_local.sin_port = htons(port); // Port number
	addr_local.sin_addr.s_addr = INADDR_ANY; // AutoFill local address

	/* Bind a special Port */
	rc = bind(sock, (struct sockaddr*)&addr_local, sizeof(addr_local));
	if (rc == SOCKET_ERROR)
		fatal("bind()");
	std::printf("[Server] Bind to all addresses, port %d\n", port);

	/* Listen remote connect/calling */
	rc = listen(sock, BACKLOG);
	if (rc == SOCKET_ERROR)
		fatal("listen()");
	std::printf ("[Server] Listening\n");

	while (1) {
		/* Wait a connection, and obtain a new socket file despriptor for single connection */
		struct sockaddr_in addr_remote;
		socklen_t size_remote = sizeof(addr_remote);
		SOCKET client = accept(sock, (struct sockaddr*)&addr_remote, &size_remote);
		if (client == SOCKET_ERROR)
			fatal("accept()");

		std::printf("[Server] Server has got connected from %s.\n", inet_ntoa(addr_remote.sin_addr));
		std::thread worker{handle_client, client}; /* handler closes client socket */
		worker.detach();
	}

#ifdef _WIN32
	::closesocket(sock);
#else
	close(sock);
#endif
}

void do_hello(SOCKET client, const char* in);
void do_run(SOCKET client, const char* in);
void do_bye(SOCKET client, const char* in);

// Read client request -- our id from the client's point of view: host:port
// Send "id random-rating"
void handle_client(SOCKET client) {
	char in[LENGTH];
	ssize_t nbytes;

	while (true) {
		// read client request
		try {
			nbytes = ::recv(client, in, sizeof(in), 0);
			if (nbytes < 1)
				fatal("recv()");
			in[nbytes] = '\0';

			if (strncmp("HELLO: ", in, 7) == 0) {
				do_hello(client, in + 7);
			} else if (strncmp("RUN: ", in, 5) == 0) {
				do_run(client, in + 5);
			} else if (strncmp("BYE: ", in, 5) == 0) {
				do_bye(client, in + 5);
			}
		}
		catch (const std::exception& e) {
			nbytes = ::send(client, e.what(), strlen(e.what()), 0);
			break;
		}
	}

#ifdef _WIN32
	::closesocket(client);
#else
	close(client);
#endif
}

void do_hello(SOCKET client, const char* in) {
	// reqeust has: "host:port"
	// reply has:   "host:port weight"
	std::ostringstream os;
	os << "HELLO: " << in << ':' << (std::rand() % 10);
	std::string out = os.str();

	ssize_t nbytes = ::send(client, out.c_str(), out.size(), 0);
	if (nbytes != static_cast<int>(out.size()))
		fatal("send()");
}

void do_run(SOCKET client, const char* /*in*/) {
	// reqeust has: "work to do"
	// reply has:   "result"
	sleep(std::rand() % 3);
	std::string out{"42"};

	ssize_t nbytes = ::send(client, out.c_str(), out.size(), 0);
	if (nbytes != static_cast<int>(out.size()))
		fatal("send()");
}

void do_bye(SOCKET /*client*/, const char* /*in*/) {
	// send message, close connection
	throw std::runtime_error{"BYE:\n"};
}

Last edited on
Topic archived. No new replies allowed.