I want to make a server and client program with TCP protocol using C++. The server must be able to handle multiple client at once. But the problem is for example, after starting the server, I run 2 clients with the server 's IP address and port as parameters. Next, both clients are sending data to server. At first, both clients could send data to server and the server was able read the data. But, once the server has received data from the second client, it seems that it stopped receiving from the first client. Do you have any solution?
Here is the server code
using namespace std;
void *task1(void *);
static int connFd;
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char* argv[])
{
int pId, portNo, listenFd;
socklen_t len; //store size of the address
bool loop = false;
struct sockaddr_in svrAdd, clntAdd;
pthread_t threadA[3];
if (argc < 2)
{
cerr << "Syntam : ./server <port>" << endl;
return 0;
}
portNo = atoi(argv[1]);
if((portNo > 65535) || (portNo < 2000))
{
cerr << "Please enter a port number between 2000 - 65535" << endl;
return 0;
}
//create socket
listenFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(listenFd < 0)
{
cerr << "Cannot open socket" << endl;
return 0;
}
bzero((char*) &svrAdd, sizeof(svrAdd));
svrAdd.sin_family = AF_INET;
svrAdd.sin_addr.s_addr = INADDR_ANY;
svrAdd.sin_port = htons(portNo);
//bind socket
if(bind(listenFd, (struct sockaddr *)&svrAdd, sizeof(svrAdd)) < 0)
{
cerr << "Cannot bind" << endl;
return 0;
}
listen(listenFd, 5);
int noThread = 0;
while (noThread < 3)
{
socklen_t len = sizeof(clntAdd);
cout << "Listening" << endl;
//this is where client connects. svr will hang in this mode until client conn
connFd = accept(listenFd, (struct sockaddr *)&clntAdd, &len);
if (connFd < 0)
{
cerr << "Cannot accept connection" << endl;
return 0;
}
else
{
cout << "Connection successful" << endl;
}
pthread_create(&threadA[noThread], NULL, task1, NULL);
noThread++;
}
for(int i = 0; i < 3; i++)
{
pthread_join(threadA[i], NULL);
}
}
void *task1 (void *dummyPt)
{
cout << "Thread No: " << pthread_self() << endl;
char test[256];
bzero(test, 256);
bool loop = false;
while(!loop)
{
bzero(test, 256);
int n = read(connFd, test, 255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",test);
}
cout << "\nClosing thread and conn" << endl;
close(connFd);
}
And the client code
using namespace std;
int main (int argc, char* argv[])
{
int listenFd, portNo;
bool loop = false;
struct sockaddr_in svrAdd;
struct hostent *server;
if(argc < 3)
{
cerr<<"Syntax : ./client <host name> <port>"<<endl;
return 0;
}
portNo = atoi(argv[2]);
if((portNo > 65535) || (portNo < 2000))
{
cerr<<"Please enter port number between 2000 - 65535"<<endl;
return 0;
}
//create client skt
listenFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(listenFd < 0)
{
cerr << "Cannot open socket" << endl;
return 0;
}
server = gethostbyname(argv[1]);
if(server == NULL)
{
cerr << "Host does not exist" << endl;
return 0;
}
bzero((char *) &svrAdd, sizeof(svrAdd));
svrAdd.sin_family = AF_INET;
bcopy((char *) server -> h_addr, (char *) &svrAdd.sin_addr.s_addr, server -> h_length);
svrAdd.sin_port = htons(portNo);
int checker = connect(listenFd,(struct sockaddr *) &svrAdd, sizeof(svrAdd));
if (checker < 0)
{
cerr << "Cannot connect!" << endl;
return 0;
}
//send stuff to server
for(;;)
{
char s[300];
//cin.clear();
//cin.ignore(256, '\n');
cout << "Enter stuff: ";
bzero(s, 300);
cin.getline(s, 300);
write(listenFd, s, strlen(s));
}
}
Yor connFd is a global variable, which you access from your main thread and all handling threads. This will not do! Imagine that - you've accepted the first connection and set the variable to the receiving socket. You've spawn the handling thread, which started reading. Next thing you know, another connection is coming along and you are receiving it as well! This very moment connFd points to the new connection, so the thread which is already using it will suddenly switch to the new connection! Of course it is not good.
The way to fix this problem is to pass the connection to the thread in such a way that is is not shared across threads. And easiest way of doing so is to use C++ thread class.
For example, this is code fragment illustrating the above idea:
void handle_connection(int fd) {
... <your task1 code>
}
...
std::vector<std::thread> threads;
...
int conn = accept(listenFd, (struct sockaddr *)&clntAdd, &len);
threads.push_back(std::thread(&handle_connection, conn));
...
... (in the end)
for (auto&& t : threads)
t.join();
Related
I want to create two projects with this code so that they can chat with each other, but no matter how much I send, the data does not reach the other client.
I've been thinking and trying for hours on this problem, but it doesn't work. Various multicast chat programs on the web are written in languages other than C++, some use threads and some do not. To the best of my knowledge right now, I can't understand the codes on the web.
For fear of lengthy code, the basic header file and error output function have been omitted.
// header file and function declaration
#define MAXBUF 80
SOCKADDR_IN maddr;
int main(int argc, char* argv[]) {
int port;
cout << "input port number" << endl;
cin >> port;
cout << "use port : " << port << endl;
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa))
{
err_display("WSAStartup");
return -1;
}
//create send socket
SOCKET r_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (r_sock == INVALID_SOCKET)
{
err_display(" recv socket");
return -1;
}
//create recv socket
SOCKET s_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s_sock == INVALID_SOCKET)
{
err_display(" send socket");
return -1;
}
// bind
maddr.sin_family = AF_INET;
maddr.sin_port = htons(port);
maddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(r_sock, (SOCKADDR*)&maddr, sizeof(maddr))) {
err_display("bind");
return -1;
}
// Join the Multicast address
const char* mip = "236.0.0.1";
IP_MREQ mreq;
mreq.imr_interface.s_addr = htonl(INADDR_ANY); // s_addr = 주소
// Setting Multicast address
if (!(inet_pton(AF_INET, mip, &mreq.imr_multiaddr))) {
err_display("inet_pton");
return -1;
}
// JOIN
if (setsockopt(r_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq))) {
err_display("setsockopt");
return -1;
}
while (true) {
HANDLE h1 = (HANDLE)_beginthreadex(NULL, 0, &sendf, (LPVOID)s_sock, 0, NULL);
HANDLE h2 = (HANDLE)_beginthreadex(NULL, 0, &recvf, (LPVOID)r_sock, 0, NULL);
}
closesocket(r_sock);
closesocket(s_sock);
WSACleanup();
return 0;
}
unsigned __stdcall sendf(LPVOID arg) // send thread function
{
SOCKET s_sock = (SOCKET)arg;
char mesbuf[MAXBUF];
int sendlen;
while (1)
{
// send
char mesbuf[MAXBUF];
if (fgets(mesbuf, MAXBUF - 1, stdin) == NULL)
break;
cout << "send Thread" << endl;
sendlen = strlen(mesbuf);
sendto(s_sock, mesbuf, sendlen, 0, (SOCKADDR*)&maddr, sizeof(maddr));
}
return 0;
}
unsigned __stdcall recvf(LPVOID arg) // recv thread function
{
SOCKADDR_IN paddr; // peer address
int namelen = sizeof(paddr);
SOCKET r_sock = (SOCKET)arg;
char mesbuf[MAXBUF];
int recvlen;
while (1)
{
char mesbuf[MAXBUF];
//recive
recvlen = recvfrom(r_sock, mesbuf, MAXBUF - 1, 0, (SOCKADDR*)&paddr, &namelen);
cout << "recv Thread" << endl;
if (recvlen == SOCKET_ERROR) {
err_display("recv error");
closesocket(r_sock);
break;
}
if (recvlen == 0)
{
cout << "normal close connection case" << endl;
closesocket(r_sock);
break;
}
mesbuf[recvlen] = '\0'; // string conversion
cout << "from : " << mesbuf << endl;
}
return 0;
}
The system I have to do has one tcp server and about 1000 tcp clients.
1000 clients will send data to tcp server every second.
To simulate this situation, At first I connected to tcp server with 50 sockets from a single pc with below code.
int main() {
const char *hello = "Hello from client";
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
serv_addr.sin_addr.s_addr = inet_addr("192.168.1.39");
vector<int> vec;
for ( uint8_t i = 0; i < 50; i++ ) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
if ( sock < 0 ) {
cout << "... Cant Allocated Socket\n";
return -1;
}
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
cout << "... Connection Failed \n";
return -1;
}
vec.push_back(sock);
}
for ( uint8_t i = 0; i < vec.size(); i++ ) {
send(vec[i], hello, strlen(hello), 0);
cout << "Message Send\n";
}
for ( uint8_t i = 0; i < vec.size(); i++ ) {
shutdown(vec[i], 0);
close(vec[i]);
}
return 0;
}
After the tcp clients connect to the tcp server, they send the data to the tcp server and close the socket. I can see from terminal that tcp clients can send packet without waiting(less than 10ms)
The above tcp client code can work successfully and send the data to tcp server successfully.
I show the data from the tcp client with the tcp server code below.
#define _DEF_TCP_SERVER_PORT 8080
#define _DEF_TCP_SERVER_MAX_QUEUE_LISTEN 12
bool finish_app = false;
struct TcpClient {
int clientSocket;
struct in_addr clientAddr;
};
vector<TcpClient> TcpClients;
struct _ServiceTcpServer {
bool enable;
int sock;
uint16_t connectedClient;
uint32_t sockLen;
sockaddr_in tcpServerAddr;
sockaddr_in remoteAddr;
};
struct _ServiceTcpServer _serviceTcpServer;
void init_tcp_server_socket() {
_serviceTcpServer.tcpServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
_serviceTcpServer.tcpServerAddr.sin_family = AF_INET;
_serviceTcpServer.tcpServerAddr.sin_port = htons(_DEF_TCP_SERVER_PORT);
_serviceTcpServer.sockLen = sizeof(_serviceTcpServer.remoteAddr);
int flag = 1;
for ( ;; ) {
_serviceTcpServer.sock = socket(AF_INET, SOCK_STREAM, 0);
if ( _serviceTcpServer.sock < 0 ) {
cout << "... Failed to allocate socket.\n";
this_thread::sleep_for(chrono::seconds(1));
continue;
}
if ( setsockopt(_serviceTcpServer.sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) ) {
cout << "... Set SockOpt failed.\n";
close(_serviceTcpServer.sock);
this_thread::sleep_for(chrono::seconds(1));
continue;
}
if( bind(_serviceTcpServer.sock, (sockaddr *) &_serviceTcpServer.tcpServerAddr, sizeof(_serviceTcpServer.tcpServerAddr)) == -1 ) {
cout << "... Socket bind failed.\n";
close(_serviceTcpServer.sock);
this_thread::sleep_for(chrono::seconds(1));
continue;
}
if ( listen(_serviceTcpServer.sock, _DEF_TCP_SERVER_MAX_QUEUE_LISTEN) != 0 ) {
cout << "... Socket listen failed.\n";
close(_serviceTcpServer.sock);
this_thread::sleep_for(chrono::seconds(1));
continue;
}
break;
}
cout << "Socket init done \n";
}
void tcp_user_accept_task() {
while ( finish_app == false ) {
int temp_sck = -1;
temp_sck = accept(_serviceTcpServer.sock, (sockaddr *) &_serviceTcpServer.remoteAddr, &_serviceTcpServer.sockLen);
if ( temp_sck == -1 ) {
this_thread::sleep_for(chrono::seconds(2));
continue;
}
TcpClient tcpClient;
tcpClient.clientAddr = _serviceTcpServer.remoteAddr.sin_addr;
tcpClient.clientSocket = temp_sck;
TcpClients.push_back( tcpClient );
cout << "... New connection request: " << temp_sck << endl;
++_serviceTcpServer.connectedClient;
this_thread::sleep_for(chrono::milliseconds(50));
}
}
uint8_t temp_recv[100];
void tcp_server_run() {
while ( finish_app == false ) {
for(uint16_t i = 0 ; i < _serviceTcpServer.connectedClient; i++ ) {
int temp_cs = TcpClients[i].clientSocket;
fcntl(temp_cs, F_SETFL, O_NONBLOCK);
int temp_recvLen = recv(temp_cs, temp_recv, 20, 0);
if( temp_recvLen > 0 ) {
time_t _time = chrono::system_clock::to_time_t(chrono::system_clock::now());
cout << "Message Received At:" << ctime(&_time) << " :";
cout << temp_recv << endl;
break;
} else {
this_thread::sleep_for(chrono::milliseconds(10));
}
}
if ( temp_recv[0] == 'q' ) {
finish_app = true;
}
}
close(_serviceTcpServer.sock);
}
int main() {
thread init_thread(init_tcp_server_socket);
init_thread.join();
thread accept_thread(tcp_user_accept_task);
thread run_thread(tcp_server_run);
accept_thread.join();
run_thread.join();
return 0;
}
But the problem is about 3-4 packets received in only 1 second as in the screen image.
Note:
When the code this_thread::sleep_for(chrono::milliseconds(10)); commented, the problem was solved. But since the processor is not sleep, the processor is working at 100%.
When the client is accepted, I added 10 us timeout to client recv with the code below and comment and fcntl(temp_cs, F_SETFL, O_NONBLOCK);
struct timeval _timeval;
_timeval.tv_sec = 0;
_timeval.tv_usec = 10;
setsockopt(tcpClient.clientSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*) &_timeval, sizeof(_timeval));
The problem continues as in "this_thread::sleep_for".
You should receive the socket simultaneously rather than querying every socket and sleeping for 10ms each time data is not yet ready.
The proper way to do it depends on the platform
posix - select
linux - poll, epoll, io_submit
windows - I/O Completion Ports
Usually, select which is a posix standard, will be sufficient for your needs.
If you want multiplatform you might also want to explorer 3rd party libraries such as libevent and libev which already wraps theses platform depent calls for you.
Happy Coding!
I'm writing a client server udp application in c++. The application works correctly when the client and server are running on the same machine, however when I run my client on my laptop and the server on an ec2 instance in AWS, the server receives 4 messages and then begins to hang on recvfrom. The client is sending a file in chunks of 500 bytes and the server is writing these to a file. The server sends an ack after it receives each chunk. The client has a timeout of 2 seconds, if it does not receive the ack before the timeout it resends the previous chunk. Here is my client code
void Sender::send_file(const char* host) {
cout << "in send file\n";
int sock = 0;
struct sockaddr_in serv_addr;
size_t length = 8;
unsigned char res_buf[8] = {0};
if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
std::cout << "\n Socket creation error \n";
exit(EXIT_FAILURE);
}
struct timeval tv;
tv.tv_sec = timeout;
tv.tv_usec = 0;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
// copy 0 into serv_addr members
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
serv_addr.sin_addr.s_addr = inet_addr(host);
size_t file_size = buffer.size();
cout << "file size " << to_string(file_size) << "\n";
size_t file_pos = 0;
int next_iteration = 1;
bool establish = true;
while(file_pos < file_size - 1) {
cout << "waiting for lock\n";
std::unique_lock<std::mutex> lock(mrun);
main_ready.wait(lock, [&next_iteration, this]{return next_iteration == current_iteration; });
lock.unlock();
cout << "acquired lock\n";
++next_iteration;
Segment segment;
vector<unsigned char> req_str;
if(!establish) {
if(file_pos + mss < file_size) {
std::vector<unsigned char> file_chunk(buffer.begin() + file_pos, buffer.begin() + file_pos + mss);
segment.data = file_chunk;
file_pos += mss;
}
else {
std::vector<unsigned char> file_chunk(buffer.begin() + file_pos, buffer.end());
segment.data = file_chunk;
file_pos = file_size;
}
segment.seq_num = file_pos - mss;
req_str = segment.to_bytes(false, mss);
}
else {
segment.seq_num = 0;
req_str = segment.to_bytes(true, mss);
}
bool is_ack = false, timed_out = false;
std::chrono::high_resolution_clock::time_point start_time, end_time;
long duration = 0;
unsigned char* req = req_str.data();
size_t num_bytes = req_str.size();
unsigned int len = 0;
while(!is_ack) {
cout << "about to send data " << std::to_string(segment.seq_num) << " bytes " << std::to_string(num_bytes) << "\n";
ssize_t send_res = sendto(sock, req, num_bytes, 0, (const struct sockaddr *) &serv_addr, sizeof(serv_addr));
printf("Sent to %s:%d\n", inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port));
cout << "send res " << to_string(send_res) << " " << strerror(errno) << "\n";
start_time = std::chrono::high_resolution_clock::now();
bzero(res_buf, length);
cout << "about to read ack\n";
ssize_t block_sz = recvfrom(sock, res_buf, length, 0, (struct sockaddr *) &serv_addr, &len);
cout << "read ack\n";
end_time = std::chrono::high_resolution_clock::now();
duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count();
cout << "block sz " << std::to_string(block_sz) << " duration " << std::to_string(duration) << std::endl;
if(duration > timeout * 1000)
timed_out = true;
if(timed_out || errno == ETIMEDOUT || block_sz < 0) {
std::cout << "time out/error occurred on read " << to_string(errno) << "\n";
cout << strerror(errno) << "\n";
bzero(res_buf, length);
timed_out = false;
continue;
}
//add_nulls(res_buf);
is_ack = read_response(segment.seq_num, res_buf);
cout << "is ack " << is_ack << "\n\n";
bzero(res_buf, length);
}
establish = false;
lock.lock();
if(--worker_count == 0) {
lock.unlock();
iteration_complete.notify_one();
}
}
cout << "Out of while loop\n";
close(sock);
files_sent.push_back(1);
}
It's sending exactly 508 bytes every time, except for the 1st segment which is only 10 bytes. I print the results of sendto after every iteration which always looks like this
Sent to 52.0.0.0:7735
send res 508 Undefined error: 0
* **Update ***
Once the server begins to hang in recvfrom and the client times out waiting for the ack, the client begins to print the following error continuously as it keeps resending the chunk.
Sent to 52.0.0.0:7735
send res 508 Resource temporarily unavailable
The server code looks like
void Receiver::download_file() {
int server_fd;
struct sockaddr_in serv_addr, cli_addr;
int segment_size = 20;
umap seg_map;
ACK_Segment::init_static();
std::random_device rd; //Will be used to obtain a seed for the random number engine
std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
std::uniform_real_distribution<> dis(0.0, 1.0);
if((server_fd = socket(AF_INET, SOCK_DGRAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
memset(&serv_addr, 0, sizeof(serv_addr));
memset(&cli_addr, 0, sizeof(cli_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(PORT);
// bind socket to port
//bzero(buffer, segment_size);
ssize_t block_sz = 0;
unsigned int len = sizeof cli_addr;
bool is_set_mss = true;
if(bind(server_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
//unsigned char* buffer = bvec.data();
vector<unsigned char> bvec(segment_size);
unsigned char* buffer = bvec.data();
bool is_resized = false;
while(true) {
cout << "about to recvfrom\n";
printf("Receiving from %s:%d\n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
cout << "segment size " << to_string(segment_size) << " len " << to_string(len) << "\n";
block_sz = recvfrom(server_fd, buffer, segment_size, 0, ( struct sockaddr *) &cli_addr, &len);
cout << "block size " << to_string(block_sz) << "errno " << to_string(errno) << " " << strerror(errno) << "\n";
if(block_sz > 0) {
cout << "Received data - bytes " << std::to_string(block_sz) << "\n";
printf("Received from %s:%d\n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
double rand_val = dis(gen);
if(is_set_mss) {
seg_map = read_segment(bvec, block_sz, true);
if(seg_map["checksum_valid"] == "true") {
segment_size = mss + HEADER_SIZE;
is_resized = true;
}
}
else {
if(block_sz == 0) {
cout << "received no data\n";
break;
}
seg_map = read_segment(bvec, block_sz, false);
}
if(seg_map["checksum_valid"] == "false")
cout << "invalid checksum\n";
else if(is_set_mss) {
vector<unsigned char> ack = get_ack();
//remove_nulls(ack);
unsigned char* ack_bytes = ack.data();
cout << "about to send ack\n";
sendto(server_fd, ack_bytes, 8, 0, (const struct sockaddr *) &cli_addr, len);
//send(new_socket, ack, 8, 0);
is_set_mss = false;
}
else {
if(seg_map["in_order"] == "true") {
string data = seg_map["data"];
std::ofstream out;
out.open(file_name, std::ios_base::app);
out << data;
out.close();
cout << "Done writing file chunk\n";
}
vector<unsigned char> ack = get_ack();
unsigned char* ack_bytes = ack.data();
sendto(server_fd, ack_bytes, 8, 0, (const struct sockaddr *) &cli_addr, len);
}
if(is_resized) {
bvec.resize(segment_size);
is_resized = false;
}
bvec.clear();
buffer = bvec.data();
cout << "Cleared buffer\n\n";
}
cout << "out of inner while\n";
}
}
This prints
Receiving from 168.0.0.0:18832
segment size 508 len 16
block size 508 errno 0 Success
However it only prints this 4 times, then it hangs on recvfrom while the client continues to send 508 bytes, and the segment size remains at 508 in recvfrom. Why would recvfrom start out working and then all of the sudden stop?
Update
I watered this down to the simplest udp client server I could write, here is the client:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <vector>
#include <iostream>
#include <cstring>
#include <string>
using std::vector;
using std::cout;
using std::to_string;
int main() {
int sock = 0;
struct sockaddr_in serv_addr;
size_t length = 11;
unsigned char res_buf[11] = {0};
if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
std::cout << "\n Socket creation error \n";
exit(EXIT_FAILURE);
}
struct timeval tv;
tv.tv_sec = 2;
tv.tv_usec = 0;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
// copy 0 into serv_addr members
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(7735);
serv_addr.sin_addr.s_addr = inet_addr("52.71.240.175");
vector<unsigned char> req(20);
for(int i = 0; i < 20; i++)
req[i] = 'A';
unsigned char* req_str = req.data();
size_t num_bytes = req.size();
unsigned int len = sizeof serv_addr;
while(true) {
cout << "about to send data\n";
ssize_t send_res = sendto(sock, req_str, num_bytes, 0, (const struct sockaddr *) &serv_addr, sizeof(serv_addr));
bzero(res_buf, length);
cout << "about to read ack\n";
ssize_t block_sz = recvfrom(sock, res_buf, length, 0, (struct sockaddr *) &serv_addr, &len);
cout << "received " << res_buf << "\n";
}
}
And here is the server:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <vector>
#include <iostream>
#include <cstring>
#include <string>
using std::vector;
using std::cout;
using std::to_string;
int main() {
int server_fd;
struct sockaddr_in serv_addr, cli_addr;
int segment_size = 20;
memset(&serv_addr, 0, sizeof(serv_addr));
memset(&cli_addr, 0, sizeof(cli_addr));
if((server_fd = socket(AF_INET, SOCK_DGRAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(7735);
unsigned int len = sizeof cli_addr;
if(bind(server_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
vector<unsigned char> bvec(segment_size);
unsigned char* buffer = bvec.data();
while(true) {
cout << "about to receive from\n";
ssize_t block_sz = recvfrom(server_fd, buffer, segment_size, 0, ( struct sockaddr *) &cli_addr, &len);
if(block_sz > 0) {
printf("Received from %s:%d\n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
char* ack_bytes = "ack message";
cout << "about to send ack\n";
sendto(server_fd, ack_bytes, 11, 0, (const struct sockaddr *) &cli_addr, len);
}
}
}
And the same behavior happens, the server receives 4 messages, but then on the fifth message it just hangs in recvfrom. I've tried closing and reopening the socket in each iteration on the server, that had no effect.
I had to close and reopen the socket on the client side after receiving each ack from the server. I didn't need to close and reopen on the server side. I'm not sure if this addresses the root cause of the problem I was facing but it allows my application to run correctly.
I having issues creating an echo program using socket programming. I do not have any error coded appear when I run the socket(), bind(), and listen() command. All of them return an integer, value 3. The part that is causing the issue in the accept() command. To test this program, I have ran the executable as a background process and run telnet to test the socket connection. The program is freezing at the accept() command. Can anyone help?
// Include all of the headers required
#include "echo_s.h"
// simple logger
#include "log.h"
// ***
// Class ClientConnection
// - created to help simply methods and functions used to create TCP connection
// for this program to work
class ClientConnection {
public:
void createSocket();
void setupAddress();
void bindSocket();
void listenSocket();
void waitingConnection();
int processConnection(int connection);
private:
int sock = -1; // file descriptor for the server
int lst = -1; // file descriptor for the listener
struct sockaddr_in
{
short family; // address family
u_short port; // port number
struct in_addr sin_addr; // internet address
char sin_zero[8];
};
struct sockaddr_in servAddr; // struct needed for the server addr
struct sockaddr_in clientAddr; // struct needed for the listener addr
char buffer[256];
};
Log* logger = new Log();
// ***
// main ()
// - sets up the socket and accepts new connection until CLOSE or QUIT
int main (int argc, char *argv[])
{
// Process the command arguments
int opt = 0;
ClientConnection client;
while ((opt = getopt(argc, argv, "v")) != -1)
{
switch (opt)
{
case 'v':
logger->setLogger(true);
logger->printLog("Verbose Action captured");
break;
case ':':
case '?':
default:
std::cout<< "Invalid option: " << argv[0] << std::endl;
exit(-1);
}
}
// create the socket
client.createSocket();
// set up socket address
client.setupAddress();
// bind socket
client.bindSocket();
// listen socket
client.listenSocket();
// Wait for the connection with the accept call
client.waitingConnection();
}
void ClientConnection::createSocket ()
{
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
logger->printLog ("Error opening socket");
exit (-1);
}
else
{
logger->printLog("Socket was created");
logger->printLog("Socket info: " + std::to_string(sock));
}
}
void ClientConnection::setupAddress ()
{
// define the struct
srand(time(NULL));
int port = (rand() % 10000 + 1024);
// zero the whole struct
bzero((char *)&servAddr, sizeof(servAddr));
// Fill in the struct with the information need for the address of the host
servAddr.family = AF_INET;
servAddr.sin_addr.s_addr = INADDR_ANY;
servAddr.port = htons(port);
logger->printLog("Address has been created for socket");
}
void ClientConnection::bindSocket ()
{
int bindSuccess = 0;
int attempts = 0;
std::string errorString;
if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
{
errorString = strerror(errno);
logger->printLog("bind() failed: " + errorString);
exit(-1);
}
else
{
logger->printLog("bind() successful");
logger->printLog("Bind() function returned: " + std::to_string(sock));
std::cout << "Port number: " << servAddr.port << std::endl;
}
}
void ClientConnection::listenSocket ()
{
int listenSocket = 5;
std::string errorString;
if (listen(sock, listenSocket) < 0)
{
errorString = strerror(errno);
logger->printLog("listen() failed: " + errorString);
exit(-1);
}
else
{
logger->printLog("listen() successful");
logger->printLog("listen() fucntion returns: " + std::to_string(sock));
}
}
void ClientConnection::waitingConnection ()
{
logger->printLog("Attempting accept()");
int quit = -1;
int attempts = 0;
socklen_t sizeClient = sizeof(clientAddr);
while(quit == -1)
{
logger->printLog("Inside while loop");
//lst = accept(sock, (struct sockaddr *) &servAddr, sizeof(servAddr));
lst = accept(sock, (struct sockaddr *) NULL, NULL);
logger->printLog("accept() function reurns: " + std::to_string(lst));
if (lst < 0)
{
std::string errorString = strerror(errno);
logger->printLog(errorString);
attempts++;
exit(-1);
}
else
{
logger->printLog("accept() successful");
quit = processConnection(lst);
}
}
}
int ClientConnection::processConnection(int connection)
{
std::cout << "connection made. TEST" << std::endl;
int n = 0;
if ((n = read(connection, buffer, 255)) < 0)
{
logger->printLog("Error reading data");
}
else
{
std::string message = buffer;
logger->printLog(message);
if (message.find("QUIT"))
{
close(connection);
return 1;
}
if (message.find("CLOSE"))
{
close(connection);
return 0;
}
n = write(connection, buffer, sizeof(buffer));
}
return 0;
}
`
When I do a select on a socket it creates a thread. When I close the socket it does not release the thread.
I am running the code in cygwin. At the first pause I attach gdb and there are three threads (not sure why three). I quit gdb and continue the program which opens does the following: open socket, bind, select, close. I then hit the second pause and then attach gdb and there are now four threads. I have even added a shutdown. I am sure that I am missing something simple but I can't seem to find it.
Here is the code.
#include <netdb.h>
#include <fstream>
#include <iostream>
#include <shlobj.h>
using namespace std;
void mySleep(int miliSeconds)
{
usleep(miliSeconds * 1000);
}
void mySleep(int miliSeconds)
{
// Sleep(miliSeconds);
usleep(miliSeconds * 1000);
}
void myPause()
{
cout << "Paused, hit enter to continue..."<< endl;
getchar();
}
int main()
{
myPause();
struct sockaddr_in serv_addr, client_addr;
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(10000);
client_addr.sin_addr.s_addr = htonl(INADDR_ANY);
struct hostent* server = gethostbyname("127.0.0.1");
memset((char *) &serv_addr, 0, sizeof (serv_addr));
serv_addr.sin_family = AF_INET;
memcpy((char *)&serv_addr.sin_addr.s_addr, (char *) server->h_addr, server->h_length);
serv_addr.sin_port = htons(10000);
int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sockfd < 0)
{
cout << "Error opening socket" << endl;
exit(-1);
}
int retCode;
socklen_t sockAddrLen = sizeof(sockaddr_in);
retCode = bind(sockfd, (const struct sockaddr *) &client_addr, sockAddrLen);
if (retCode < 0)
{
cout << "Unable to bind" << endl;
close(sockfd);
exit(-1);
}
struct timeval tv;
fd_set socks;
FD_ZERO(&socks);
FD_SET(sockfd, &socks);
tv.tv_sec = 5;
tv.tv_usec = 0;
retCode = select(sockfd + 1, &socks, NULL, NULL, &tv);
if (retCode < 0)
{
cout << "Unable to select" << endl;
close(sockfd);
exit(-1);
}
retCode = shutdown(sockfd, 2); // 2 = stop both reception and transmission
if (retCode < 0)
{
cout << "Unable to shutdown" << endl;
close(sockfd);
exit(-1);
}
retCode = close(sockfd);
if (retCode < 0)
{
cout << "Unable to close" << endl;
close(sockfd);
exit(-1);
}
sockfd = -1;
mySleep(5000);
myPause();
return 0;
}
Closing a UDP socket simply doesn't cause a select on that socket to end. I'm unclear why, but this is expected behavior. See this older question