Client/Server communication sending the wrong values to client

I wrote a client and server. The only issue I'm having is that when I look through my vector of structs for a value that was requested by the client in the table, it is not returning that value. I was hoping you guys could take a look and point me in the right direction. Also, I'm not sure why but when saving the data from the file into the vector it saves the last value twice.

Client code
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
#include <iostream>
#include <string>
#include <cstring>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>


using namespace std;

int main(){
	string hostname, nbhd;
	int pnum;
	
	cout << "Enter server hostname: ";
	cin >> hostname;
	
	cout << "\nEnter server port number: ";
	cin >> pnum;
	
	const char* chostname = hostname.c_str();
	
	
	
	// Initializing my socket
	int sockfd, portno, n;
	struct sockaddr_in serv_addr;
	struct hostent *server;
	char buffer[256];
	
	/*if (argc < 3){
		fprintf(stderr,"usage %s hostname port\n", argv[0]);
		exit(0);
	}*/
	
	portno = pnum;
	
	//Create a socket point
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	
	if(sockfd < 0){
		perror("ERROR opening socket");
		exit(0);
	}
	
	server = gethostbyname(chostname);
	
	bzero((char *) &serv_addr, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	bcopy((char *)server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length);
	serv_addr.sin_port = htons(portno);
	
	// Now connect to the server
	if (connect(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0){
		perror("ERROR connecting");
		exit(1);
	}
	
	// Asking for a message from the user, message will be read by the server
	int i=0;
	while(1){
		cout << endl;
		
		printf("Enter a Houston neighborhood: ");
		if(i == 0){
			bzero(buffer,256);
			getchar();
			fgets(buffer,255,stdin);
		}
		else{
			bzero(buffer,256);
			fgets(buffer,255,stdin);
		}
		
		if(buffer[0] == '\n'){
			close(0);
			exit(0);
		}
	
	//Send message to the server
	
		n= write(sockfd, buffer, strlen(buffer));
	
		if(n < 0){
			perror("ERROR writing to socket");
			exit(1);
		}
		
		// Read server response
		bzero(buffer,256);
		n = read(sockfd, buffer, 255);
		if(buffer[0] == '-' && buffer[1] == '1'){
			cout << "The neighborhood is not in the table.";
		}
		else{
			cout << "The average price of the houses is " << buffer;
		}
	
		if (n < 0) {
			perror("ERROR reading from socket");
			exit(1);
		}
		i++;
		//printf("%s\n",buffer);
	}
	
	

	
	return 0;
}


server code

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

#include <iostream>
#include <string>
#include <cstring>
#include <fstream>
#include <vector>
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>


using namespace std;

//To hold info on the neighborhood
struct houseinfo {
	string neighborhood;
	string nprice;
};



int main(){
	string file, nbhd, nbhdprice;
	int portnum;
	struct houseinfo house;
	vector<struct houseinfo> htable;
	
	
	cout<< "Please enter the name of the file: ";
	cin >> file;
	
	ifstream myfile (file);
	
	if(myfile.is_open()){
		while(myfile.good()){
			getline(myfile,nbhd, ',');
			house.neighborhood = nbhd;
			getline(myfile,nbhdprice);
			house.nprice = nbhdprice;
			htable.push_back(house);
		}
		myfile.close();
	}
	
	/*for(unsigned int i=0;i<htable.size();i++){
		cout << htable[i].neighborhood << " " << htable[i].nprice << endl;
	}*/
	
	cout << "\nEnter server port number: ";
	cin >> portnum;
	
	//creating the socket
	int sockfd, newsockfd, portno;
	socklen_t clilen;
	char buffer[256];
	struct sockaddr_in serv_addr, cli_addr;
	int n;
	
	//first call to socket() fucntion
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	
	if(sockfd < 0){
		perror("ERROR opening socket");
		exit(1);
	}
	
	// Initialze socket structure
	bzero((char *) &serv_addr, sizeof(serv_addr));
	portno = portnum;
	
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = INADDR_ANY;
	serv_addr.sin_port = htons(portno);
	
	//now bind the host address using bind() call
	
	if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr))<0){
		perror("ERROR on binding");
		exit(1);
	}
	
	//listening for the clients, going to sleep mode and wating for incoming connection
	listen(sockfd,5);
	clilen = sizeof(cli_addr);
	
	// Accept actual connection from the client
	newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
	
	if(newsockfd < 0){
		perror("ERROR on accept");
		exit(1);
	}
	while(1){
	//If connection is established then start communication
		bzero(buffer,256);
		
		n = read(newsockfd,buffer,255);
		
		if(buffer[0] == '\n'){
			exit(0);
		}
	
		if(n < 0){
			perror("ERROR reading from socket");
			exit(1);
		}
		
		
	//Write a response to the client
		printf("Here is the message: %s",buffer);
		string cprice;
		const char* dprice;
	//Searching for the price of the neighborhood
		for(unsigned int i=0; i < htable.size();i++){
			if(htable[i].neighborhood == buffer){
				cprice = htable[i].nprice;
				//cout<< cprice;
				dprice = cprice.c_str();
				//cout << endl << dprice;
				break;
			}
			else{
				dprice = "-1";
			}
		}
		//cout << endl << dprice;
		n = write(newsockfd, dprice,255);

	
		if(n < 0){
			perror("ERROR writing to socket");
			exit(1);
		}
	}
	
	//closing my socket
	close(0);
	
	return 0;
}


input file can be downloaded here https://piazza-resources.s3.amazonaws.com/j2wrl2jph8w578/j52q91jqgiw3lv/input2.txt?AWSAccessKeyId=AKIAIEDNRLJ4AZKBW6HA&Expires=1500855375&Signature=MCPSw1IrQ6kVWzVWyVsxrhcqXmA%3D

But the following is just part of the sample file in case you don't want to download it all.


Acres Home, 123910
Addicks/ Park Ten, 210431
Afton Oaks/ River Oaks, 1645821
Airline Farms, 575000
Aldine Meadows, 199000
Alief, 135940
Altamira, 210659
Amesbury Park, 340492
Astrodome, 179246
Atascocita Greens, 242900
Atascocita North, 133088
Atascocita Shores, 400831
Atascocita South, 174055
Atascocita Timbers, 157900
Atascocita Trails, 202933
Bammel Village, 139900
Bear Creek Village, 177243
Beckford Place, 102000
Beechnut Landing, 191950
Bell Mead, 550000
Bending Bough, 372450
Berkshire, 276696
Binz, 536143
Birdsall, 724900
Bonaire, 159000
Braeburn, 219687
Braeswood Place, 629610
Briarforest, 383506
Brunswick Lakes, 194020
Camden Park, 145000
Canyon Gate At Northpointe, 231455
Last edited on
The only issue I'm having is ...

You have a few problems.

socket(AF_INET, SOCK_STREAM, 0); should be socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);. But your code will still work as is because IPPROTO_TCP is deduced by the underlying factory and PF_INET == AF_INET.

You're using bzero without including strings.h. I'm surprised it compiles. Evidently, it's being pulled in by another header file.

Use sizeof(buffer) rather specifying numbers.

Your server should call accept in a loop. As it stands, it will handle one request then terminate.

TCP is a stream protocol. That means, there are no records, no messages, ... you have to delimit the data according to your own scheme. Your client just sends a sequence of bytes without a length or a null terminator. The server sees the message because the sequence is short (within an ethernet frame) and the buffer is already cleared. But you should understand that what you have done isn't the best.

I think nprice in the table is being stored with a leading space, or just the space, I'm not sure. But the parsing isn't quite right. Have you printed the values in htable or looked at them with a debugger?

The server tries to write dprice, but dprice is a string, not a buffer, so you must call dprice.c_str() and pass the right length (dprice.size() + 1?)

EDIT:
Ok, dprice isn't a string, but it isn't being used correctly. Get rid of it and use cprice directly. To send cprice with the null terminator:
 
send(socket, cprice.c_str(), cprice.size() + 1, 0);
Last edited on
Hi Kbw,

I was just following the example on this webpage

https://www.tutorialspoint.com/unix_sockets/socket_server_example.htm

This is my first time building a server/client so I understand I will have a whole lot of bad practices/errors.

Regarding the bzero part of the code, I am using strings.h library if you look carefully in the include files it is there as the last library to be implemented.

Using sizeof(buffer) this hadn't occured to me, I'll be sure to implement it. I would add it to the last part of the n = write(newsockfd, dprice, sizeof(buffer)); correct?

you have to delimit the data according to your own scheme. Your client just sends a sequence of bytes without a length or a null terminator.


What do you mean? What would be the best practice?

I have printed out the values for the nprice and neighborhood yes there is a leading space for nprice but I don't think that should be an issue since I'm searching for the neighborhood and just sending the price.


I didn't see strings.h, but you do have string.h twice. They're different files. string.h is the ANSI C header containing string definitions. strings.h originally came from BSD. The b in bzero and bcopy mean BSD. The ANSI alternatives are memset and memcpy.

You have to understand how your data is held in the computer and design a method of passing that representation across the wire to another computer. This process is call serialization.

A C string is held as a sequence of characters with a NULL as the last character. This is commonly called a null terminated string. This Abstract Data Type is used in the C runtime library. There is a set of functions that manipulate these, strcpy, strcat, strlen and so on. These were originally Unix calls, but have been ANSI C since 1989.

std::string holds a sequence of bytes. The object maintains pointers to the start and end of the sequence. There's a c_str() method to provide a C string representation to interoperablity with C.

TCP is a stream protocol. That means, it just passes sequences of bytes in order. There are no messages, no records. A client sending 3 writes doesn't necessarily correspond to 3 reads on the server. The network is free to coalese the data into a single read on the server. So how does the other side know when it's received all the data? You must devise a scheme that the two sides use to guarantee correct communication, this is called a protocol.

To get string from one computer to another, using TCP, means passing this information in a generic way. For example, you could pass the length, then the sequence of bytes. Or you could pass the full null terminated. So the null becomes the delimiter.

Let's look a real world example, HTTP. Version 1.1 of the spec allows you to send a request with a number of options. HTTP sends each section with a \r\n terminator, and the whole sequence is terminated with \r\n\r\n.

The server will continue to read until it sees this sequence. An once it has the full request, it parses the request and processes it.

The point of all this is, you can't just send the characters of the string without some means of the other side knowing how when to stop reading.

At the moment, your client sends just the chars in the string, and the server sends 255 bytes, the first few have the characters, the remaining majority are just null.
@kbw

Thanks for helping me out and clearing things out for me. Thanks to your help I was able to figure out and understand the assignment a lot better.
Topic archived. No new replies allowed.