Receiving UDP Packets Asynchronously From Multiple File Descriptors - c++

I have a questions about using fcntl and sigaction to receive a UDP packet asynchronously. In my program I have two sources of UDP traffic that I would like to monitor. I have set up two sockets for the traffic and used this tutorial to set the file descriptor to trigger a sigaction whenever I receive a UDP packet.
This works fine with only one source, but when I add the other source it will trigger only one of the handlers whenever either file descriptor receives a packet.
Here is a short program demonstrating the behavior:
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int done;
int a_fd;
int b_fd;
int recv_dgram(int fd, char* dgram, int size)
{
struct sockaddr_in addr;
int fromlen = sizeof(addr);
return recvfrom(fd, dgram, size, 0, (struct sockaddr*)&addr, (socklen_t*)&fromlen);
}
void a_handler(int signum)
{
char dgram[256];
int size = recv_dgram(a_fd, dgram, 256);
printf("a recieve size: %d\n", size);
}
void b_handler(int signum)
{
char dgram[256];
int size = recv_dgram(b_fd, dgram, 256);
printf("b recieve size: %d\n", size);
}
void sig_handle(int signum)
{
done = 1;
}
int init_fd(int port, const char* group, const char* interface)
{
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if(fd < 0) {
return -1;
}
int reuse = 1;
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) < 0) {
close(fd);
return -1;
}
if(fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
close(fd);
return -1;
}
struct sockaddr_in addr;
memset((char*)&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if(bind(fd, (struct sockaddr*)&addr, sizeof(addr))) {
close(fd);
return -1;
}
struct ip_mreq mcast_group;
mcast_group.imr_multiaddr.s_addr = inet_addr(group);
mcast_group.imr_interface.s_addr = inet_addr(interface);
if(setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mcast_group, sizeof(mcast_group))) {
close(fd);
return -1;
}
return fd;
}
int main(int argc, const char* argv[])
{
done = 0;
signal(SIGINT, sig_handle);
signal(SIGTERM, sig_handle);
// make sockets and sigactions
a_fd = init_fd([a port], [a multicast group], [a interface]);
if(a_fd < 0) {
return -1;
}
pid_t pid = getpid();
int a_flags = fcntl(a_fd, F_GETFL);
fcntl(a_fd, F_SETFL, a_flags | O_ASYNC);
struct sigaction a_sa;
a_sa.sa_flags = 0;
a_sa.sa_handler = a_handler;
sigemptyset(&a_sa.sa_mask);
sigaction(SIGIO, &a_sa, NULL);
fcntl(a_fd, F_SETOWN, pid);
fcntl(a_fd, F_SETSIG, SIGIO);
b_fd = init_fd([b port], [b multicast group], [b interface]);
if(b_fd < 0) {
close(a_fd);
return -1;
}
int b_flags = fcntl(b_fd, F_GETFL);
fcntl(b_fd, F_SETFL, b_flags | O_ASYNC);
struct sigaction b_sa;
b_sa.sa_flags = 0;
b_sa.sa_handler = b_handler;
sigemptyset(&b_sa.sa_mask);
sigaction(SIGIO, &b_sa, NULL);
fcntl(b_fd, F_SETOWN, pid);
fcntl(b_fd, F_SETSIG, SIGIO);
printf("start\n");
while(!done) { pause(); }
printf("done\n");
close(a_fd);
close(b_fd);
return 0;
}
I can compile this with (you can compile using gcc too):
g++ -c test.cpp
g++ -o test test.o
I'm using g++ 4.6.3 on Ubuntu 12.04 LTS.
When I run this program with two sources of UDP data, b_handler gets triggered when either file descriptors has a packet available. So it will print "b received size: -1" whenever a_handler should receive a packet. a_handler never gets called.
I suspect that this is because getpid() will return the same value for both of them so one of the sigaction handler will be overwritten.
Is there any way I can have these two handlers trigger independent of each other?
Thanks for the help.

Use two different signals, say SIGIO and SIGUSR1.
fcntl(descriptor, SETSIG, signal_desired);

Related

What`s wrong with this socket select code?

#include <stdio.h>
#include <time.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#pragma comment(lib, "WS2_32.lib")
#define IP_ADDRESS "127.0.0.1"
#define PORT 20000
#define BUF_SIZE 64
#undef FD_SETSIZE
#define FD_SETSIZE 10000
void shuffle_buffer(char* buf, size_t size);
SOCKET create_socket();
void send_data(SOCKET sock);
int main()
{
WSADATA ws;
if (WSAStartup(MAKEWORD(2, 2), &ws) != 0)
{
printf("Init Windows Socket Failed::%d\n", GetLastError());
return -1;
}
const int CLIENT_SIZE = 1;
SOCKET socks[CLIENT_SIZE];
struct timeval tv = { 0, 10 };
fd_set fd_read, fd_write;
FD_ZERO(&fd_read);
FD_ZERO(&fd_write);
for (int i = 0; i < CLIENT_SIZE; i++) {
SOCKET sock = create_socket();
socks[i] = sock;
FD_SET(sock, &fd_write);
FD_SET(sock, &fd_read);
}
Sleep(1000);
int number_to_recv = CLIENT_SIZE;
while (number_to_recv > 0) {
int ret = select(CLIENT_SIZE, &fd_read, &fd_write, NULL, &tv);
for (int i = 0; i < CLIENT_SIZE; i++) {
if (FD_ISSET(socks[i], &fd_read)) {
char buf[BUF_SIZE];
int n = recv(socks[i], buf, BUF_SIZE, 0);
buf[n] = 0;
printf("%s\n", buf);
number_to_recv--;
}
if (FD_ISSET(socks[i], &fd_write)) {
send_data(socks[i]);
FD_CLR(socks[i], &fd_write);
//Sleep(1);
}
}
//printf("ret and number : %d, %d\n", ret, number_to_recv);
}
for (int i = 0; i < CLIENT_SIZE; i++) {
closesocket(socks[i]);
}
WSACleanup();
}
SOCKET create_socket()
{
SOCKET cli_sock;
struct sockaddr_in addr;
if ((cli_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
printf("Create Socket Failed::%d\n", GetLastError());
return -1;
}
//inet_pton
memset(addr.sin_zero, 0x00, 8);
addr.sin_family = AF_INET;
inet_pton(AF_INET, IP_ADDRESS, (void*)(&addr.sin_addr.s_addr));
addr.sin_port = htons(PORT);
if (connect(cli_sock, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
{
printf("Connect Error::%d\n", GetLastError());
return -1;
}
return cli_sock;
}
void send_data(SOCKET sock)
{
const int SEND_SIZE = BUF_SIZE / 2;
char buf[SEND_SIZE] = { 0 };
memset(buf, 'a', SEND_SIZE);
shuffle_buffer(buf, SEND_SIZE);
if (send(sock, buf, SEND_SIZE, 0) == SOCKET_ERROR)
{
printf("Send Info Error::%d\n", GetLastError());
}
}
void shuffle_buffer(char* buf, size_t size)
{
for (int i = 0; i < size; i++) {
buf[i] += int(rand() % 26);
}
}
Code above is a socket client using select model run on Win10, the problem is after I send data, but I can not receive data(I am sure that server has sent back data), this code below doesn`t run, so what is the problem? Thanks
The first parameter in select is maxfdp, and I know the difference between Win and Unix, so on Windows, this parameter seems not necessary, and I can write data,
but can not receive it.
if (FD_ISSET(socks[i], &fd_read)) {
char buf[BUF_SIZE];
int n = recv(socks[i], buf, BUF_SIZE, 0);
buf[n] = 0;
printf("%s\n", buf);
number_to_recv--;
}
select removes the sockets from the fd_set if they are not readable/writable. You need to add them back in before the next time you call select.
The reason your code can write data is because sockets start out being writable, so they will still be set in fd_write and your code will write data. They don't start out being readable, if no data has been received yet, so they'll be removed from the fd_read set and then your code stops checking whether they are readable.

my epoll server losses some connections. why?

I'd like to make an epoll server. But my code of the server losses some connections.
My client spawns 100 threads and each sends the same message. Then my server is supposed to receive and print them with counting numbers.
But the server seems like losing connections and I don't know why.
I changed EPOLL_SIZE from 50 to 200, and did backlog argument of listen() from 5 to 1000. But they didn't work.
1.server:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <memory>
#include <array>
#define BUF_SIZE 100
#define EPOLL_SIZE 200
void error_handling(const char *buf);
int main(int argc, char *argv[])
{
// Step 1. Initialization
int server_socket, client_socket;
struct sockaddr_in client_addr;
socklen_t addr_size;
int str_len, i;
char buf[BUF_SIZE];
int epfd, event_cnt;
if (argc != 2) {
printf("Usage : %s <port>\n", argv[0]);
exit(1);
}
// Step 2. Creating a socket
server_socket = socket(PF_INET, SOCK_STREAM, 0);
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(atoi(argv[1]));
// Step 3. Binding the server address onto the socket created just right before.
if (bind(server_socket, (struct sockaddr*) &server_addr, sizeof(server_addr)) == -1)
error_handling("bind() error");
// Step 4. Start to listen to the socket.
if (listen(server_socket, 1000) == -1)
error_handling("listen() error");
// Step 5. Create an event poll instance.
epfd = epoll_create(EPOLL_SIZE);
auto epoll_events = (struct epoll_event*) malloc(sizeof(struct epoll_event) * EPOLL_SIZE);
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = server_socket;
// Step 6. Adding the server socket file descriptor to the event poll's control.
epoll_ctl(epfd, EPOLL_CTL_ADD, server_socket, &event);
int recv_cnt = 0;
while(true)
{
// Step 7. Wait until some event happens
event_cnt = epoll_wait(epfd, epoll_events, EPOLL_SIZE, -1);
if (event_cnt == -1)
{
puts("epoll_wait() error");
break;
}
for (i = 0; i < event_cnt; i++)
{
if (epoll_events[i].data.fd == server_socket)
{
addr_size = sizeof(client_addr);
client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &addr_size);
event.events = EPOLLIN;
event.data.fd = client_socket;
epoll_ctl(epfd, EPOLL_CTL_ADD, client_socket, &event);
//printf("Connected client: %d\n", client_socket);
}
else // client socket?
{
str_len = read(epoll_events[i].data.fd, buf, BUF_SIZE);
if (str_len == 0) // close request!
{
epoll_ctl(epfd, EPOLL_CTL_DEL, epoll_events[i].data.fd, nullptr);
close(epoll_events[i].data.fd);
printf("%d: %s\n", ++recv_cnt, buf);
//printf("closed client: %d \n", epoll_events[i].data.fd);
}
else
{
write(epoll_events[i].data.fd, buf, str_len); // echo!
}
} // end of else()
} // end of for()
} // end of while()
close(server_socket);
close(epfd);
free(epoll_events);
return EXIT_SUCCESS;
}
void error_handling(const char *buf)
{
fputs(buf, stderr);
fputc('\n', stderr);
exit(EXIT_FAILURE);
}
2.client:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <thread>
#include <vector>
#include <algorithm>
#include <mutex>
#define BUF_SIZE 100
#define EPOLL_SIZE 50
void error_handling(const char *buf);
int main(int argc, char *argv[])
{
// Step 1. Initialization
int socketfd;
if (argc != 3) {
printf("Usage : %s <ip address> <port>\n", argv[0], argv[1]);
exit(EXIT_FAILURE);
}
std::vector<std::thread> cli_threads;
std::mutex wlock;
for (int i = 0; i < 100; i++) {
cli_threads.push_back(std::thread([&](const char* szIpAddr, const char* szPort) {
// Step 2. Creating a socket
socketfd = socket(PF_INET, SOCK_STREAM, 0);
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(szIpAddr);
server_addr.sin_port = htons(atoi(szPort));
// Step 3. Connecting to the server
if(connect(socketfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
error_handling("connect() error");
// Step 4. Writing message to the server
std::string msg = "Hey I'm a client!";
wlock.lock();
auto str_len = write(socketfd, msg.c_str(), msg.size()+1);
wlock.unlock();
close(socketfd);
}, argv[1], argv[2]));
}
std::for_each(cli_threads.begin(), cli_threads.end(),
[](std::thread &t)
{
t.join();
}
);
return EXIT_SUCCESS;
}
void error_handling(const char *buf)
{
fputs(buf, stderr);
fputc('\n', stderr);
exit(EXIT_FAILURE);
}
expected like...
1: Hey I'm a client!
...
100: Hey I'm a client!
but, the result varies, like...
1: Hey I'm a client!
...
n: Hey I'm a client!
where the n is less than 100.
You had undefined behaviour because of passing socketfd by reference to thread - std::thread([&](.... One instance of socket descriptor was being modified by all threads concurrently - it caused problems. Every thread should store its own descriptor.

Hello World UDP multicast not working

I am trying to get a very basic hello world UDP sender and UDP multicast listener to work. I have a PC but have a virtual machine with the Linux OS CentOS. It has no problems connecting to the internet. The sender and listener are two separate programs, Eclipse is my environment.
The Sender...
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#define UDP_PORT 5403
#define UDP_GROUP "225.0.0.1" // 127.0.0.1
int main(int argc, char *argv[])
{
struct sockaddr_in addr;
int fd;
struct ip_mreq mreq;
char *message="Hello, World!";
int message_size = strlen(message) + 1;
// Create a UDP socket
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0)
{
perror("socket(...) ");
return -1;
}
// allow multiple sockets to use the same PORT number
u_int reuse_port = 1;
if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &reuse_port, sizeof(reuse_port)) < 0)
{
perror("setsockopt(...) ");
return -1;
}
// set up destination address
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(UDP_GROUP);
addr.sin_port = htons(UDP_PORT);
printf("Begin sendto(...) infinite loop\n");
while (true)
{
printf("Sending message: %s, of size: %d\n", message, message_size);
if (sendto(fd, message, message_size, 0, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("sendto(...): ");
return -1;
}
// printf("message sent: %s\n", message);
sleep(1);
}
return 1;
}
The Listener...
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#define UDP_PORT 5403
#define UDP_GROUP "225.0.0.1"
#define MAX_BUFFER_SIZE 256
int main(int argc, char *argv[])
{
struct sockaddr_in addr;
int fd, nbytes;
socklen_t addrlen;
struct ip_mreq mreq;
char msgbuf[MAX_BUFFER_SIZE];
u_int reuse_port = 1;
// Create a socket
fd = socket(AF_INET,SOCK_DGRAM,0);
if (fd < 0)
{
perror("create socket failed");
return -1;
}
// allow multiple sockets to use the same PORT number
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_port, sizeof(reuse_port)) < 0)
{
perror("Reusing port number failed");
return -1;
}
// set up destination address
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(UDP_PORT);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("bind");
return -1;
}
// Set the recvfrom timeout after 1 s
struct timeval tv;
tv.tv_sec = 2;
tv.tv_usec = 0;
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
{
perror("Error setting recvfrom timeout\n");
return -1;
}
// use setsockopt() to request that the kernel join a multicast group
mreq.imr_multiaddr.s_addr = inet_addr(UDP_GROUP);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
{
perror("setsockopt");
return -1;
}
addrlen = sizeof(addr);
printf("Begin recvfrom(...) infinite loop\n");
while (true)
{
nbytes = recvfrom(fd, msgbuf, MAX_BUFFER_SIZE, 0, (struct sockaddr *)&addr, &addrlen);
if (nbytes < 0)
{
printf("recvfrom timeout\n");
}
else
{
printf("message received: %s\n", msgbuf);
}
}
return 1;
}
Every second, the sender program printf's "Sending message: Hello, World!, of size: 14" and every two seconds the receiver printf's "recvfrom timeout". I have set Wireshark to look at UDP traffic and I definitely see the sento data. The recvfrom is not getting any data. I have tried using many different Group IP's from 255.0.0.0 to 239.255.255.255, no change. I have tried many different ports, no change. Is their a special setup I need to do on my network card? I'm not sure what else to do. Small edit, the recvfrom and sendto message should not have "&".

Multithreaded winsock server not accepting clients c++

So I have a winsock application in which the computer tries to accept a client, and then starts a new thread with the a pointer to the class object with client info which it copies and then deletes with the delete keyword.
The backbone is copied but the beginning of the OOP-structure is my work and the current implementation seems to be giving me some issues.
I noticed the socket might not copy in the correct format, but have no idea on how to fix this. As the client tries to connect it throws me the error message of that the server refused the connection. Anyway, here is the code of the server.
UPDATE:
It's working.
// main.h
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <process.h>
#include <cstring>
#include <iostream>
#include <stdio.h>
#include <memory>
#pragma comment(lib,"ws2_32.lib" )
class clientData{
private:
SOCKET clientSocket;
std::string name;
public:
clientData(SOCKET &clientSock, const char *tName);
clientData(clientData *cliDat);
~clientData();
inline SOCKET *getClientSocket(){
return &clientSocket;
}
inline std::string *getName(){
return &name;
}
};
And here is the main cpp file
// main.cpp
#include "main.h"
unsigned int __stdcall ServClient(void *data);
int main(int argc, char *argv[])
{
WSADATA wsaData;
int iResult;
sockaddr_in addr;
SOCKET sock, client[10];
addr.sin_family = AF_INET;
addr.sin_port = htons(13337);
addr.sin_addr.S_un.S_addr = INADDR_ANY;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);//2.2
if (iResult)
{
printf("WSA startup failed");
return 0;
}
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET)
{
printf("Invalid socket");
return 0;
}
int addrlen = sizeof(sockaddr_in);
iResult = bind(sock, (sockaddr*)&addr, sizeof(sockaddr_in));
if (iResult)
{
printf("bind failed %u", GetLastError());
return 0;
}
iResult = listen(sock, SOMAXCONN);
if (iResult)
{
printf("iResult failed %u", GetLastError());
return 0;
}
int iterationCount = 0;
while ((iterationCount < 10 &&
(client[iterationCount] = accept(sock, (SOCKADDR*)&addr, &addrlen)) != SOCKET_ERROR))
{
if (client[iterationCount] == INVALID_SOCKET){
printf("invalid client socket",GetLastError());
continue;
}
++iterationCount;
char tempName[100] = { '\0' };
sprintf_s(tempName, sizeof(tempName), "Client %u", iterationCount);
clientData *tempCLdata = new clientData(client[iterationCount - 1], tempName);
_beginthreadex(0, 0, ServClient, (void*)tempCLdata, 0, 0);
tempCLdata = nullptr;
}
return 0;
}
unsigned int __stdcall ServClient(void *data)
{
clientData cliDat((clientData*)data);
delete (clientData*)data;
printf("Client connected\n");
int recvLen = 1;
char chunk[1024] = { '\0' };
while ((recvLen = recv(*cliDat.getClientSocket(), chunk, 1024, 0)) > 0){
printf("%.*s", recvLen, chunk);
}
if (recvLen == -1)
perror("Socket recv() problem..\n");
else
printf("End of data on socket, closing..\n");
closesocket(*cliDat.getClientSocket());
return 0;
}
clientData::clientData(SOCKET &clientSock, const char *tName){
clientSocket = clientSock;
name.assign(tName);
}
clientData::clientData(clientData *cliDat){
SOCKET *clientSocketPtr = cliDat->getClientSocket();
clientSocket = *clientSocketPtr;
name.assign(cliDat->getName()->c_str());
}
clientData::~clientData(){
}
Also here is the relevant bit of client code, as requested.
char buffer[1023] = { '\0' };
int heartbeatCount = 0;
while (true)
{
sprintf_s(buffer, sizeof(buffer), "Heartbeat %d", heartbeatCount + 1);
send(sock, buffer, strlen(buffer) + 1, 0);
++heartbeatCount;
Sleep(1000);
}

socket programming( server and client on the same computer) something wrong with connection

I'm new to socket programming and I have this client that tries to connect to a server on the same computer. But the server hangs there after bind or accept—cause bind seems to be right but no output. I know that the server works because another client can connect just fine and the client seems to have done that. What causes the server to not see this incoming connection? I'm at the end of my wits here.
And I haven't been used to programming on Mac, so thank you so much for your patience if I have made some foolish mistakes.
My code is as follows:
server.cpp
using namespace std;
#include<iostream>
#include <netinet/in.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#define PORT 8888
#define BACKLOG 20
//#define DEST_IP "127.0.0.1"
int process_conn_server(int s)
{
ssize_t size =0;
char buffer[1024];
for( ; ; )
{
size = read(s,buffer,1024);
if(size == 0)
{
return 0;
}
}
sprintf(buffer, "%d bytes altogether\n", (int)size);
write(s, buffer,strlen(buffer)+1);
return 0;
}
int main(int argc,char *argv[])
{
//cout<<"?";
int ss, sc, r, err;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int opt=1;
pid_t pid;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(PORT);
ss = socket(AF_INET, SOCK_STREAM, 0);
if(ss<0)
{
cout<<"[process infro]socket error"<<endl;
return -1;
}
cout<<"[process infro]socket successful"<<endl;
r = setsockopt(ss, SOL_SOCKET,SO_REUSEADDR, (void*)&opt,sizeof(opt));
if (r == -1)
{
perror("setsockopt(listen)");
return 0;
}
cout<<"[process infro]sockopt successful"<<endl;
cout<<"?";
err = bind(ss, (struct sockaddr*) &server_addr, sizeof( server_addr));
cout<<"err";
if(err < 0)
{
cout<<"[process infro]bind error"<<endl;
return -1;
}
cout<<"[process infro]bind successful";
err=listen(ss, BACKLOG);
if(err <0)
{
cout<<"[process infro]listen error"<<endl;
return -1;
}
cout<<"[process infro]lisen successful";
for( ; ; )
{
int addrlen = sizeof(struct sockaddr);
sc = accept(ss, (struct sockaddr*)&client_addr, (socklen_t *)&addrlen);
if(sc < 0)
{
continue;
}
pid = fork();
if (pid == 0)
{
close(ss);
process_conn_server(sc);
}
else
{
close(sc);
}
}
//opt=0;
//setsockopt(ss,SOL_SOCKET,SO_REUSEADDR,(void*)&opt,sizeof(len));
}
client.cpp
using namespace std;
#include<iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <time.h>
#include <arpa/inet.h>
#include <fstream.h>
#define PORT 8888
#define DEST_IP "127.0.0.1"
void process_conn_client(int s)
{
ssize_t size = 0;
char buffer[1024];
//read from the file to be sent
fstream outfile("programm.txt",ios::in|ios::out);
if (outfile.fail())
{
printf("[process infro]cannot open the file to be sent\n");
return ;
}
printf("[process infro]successfully open the file to be sent\n");
while(!outfile.eof())
{
outfile.getline(buffer,1025,'\n');
write(s,buffer,1024);
size = read(s, buffer, 1024);
if(size = 0)
{
return ;
}
//write to the server
write(s,buffer,size);
//get response from the server
size=read(s,buffer,1024);
write(1,buffer,size);
}
outfile.close(); //关闭文件
}
int main(int argc,char *argv[])
{
int s;
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(DEST_IP);
server_addr.sin_port = htons(PORT);
s = socket(AF_INET, SOCK_STREAM, 0);
if(s < 0)
{
cout<<"[process infro]socke error"<<endl;
return -1;
}
cout<<"[process infro] socket built successfully\n";
//inet_pton(AF_INET, argv[1], &server_addr.sin_addr);
connect(s, (struct sockaddr*)&server_addr, sizeof(struct sockaddr));
cout<<"[process infor] connected\n";
process_conn_client(s);
close(s);
return 0;
}
This may be unrelated.... but it won't fit in a comment...
In your server you do this:
int process_conn_server(int s)
{
ssize_t size =0;
char buffer[1024];
for( ; ; )
{
// keep reading until read returns 0
size = read(s,buffer,1024);
if(size == 0)
{
return 0;
}
}
sprintf(buffer, "%d bytes altogether\n", (int)size);
write(s, buffer,strlen(buffer)+1);
return 0;
}
In your client you do this:
void process_conn_client(int s)
{
ssize_t size = 0;
char buffer[1024];
//read from the file to be sent
fstream outfile("programm.txt",ios::in|ios::out);
if (outfile.fail())
{
printf("[process infro]cannot open the file to be sent\n");
return ;
}
printf("[process infro]successfully open the file to be sent\n");
while(!outfile.eof())
{
outfile.getline(buffer,1025,'\n');
// write to server?
write(s,buffer,1024);
// read from server?
size = read(s, buffer, 1024);
if(size = 0)
{
return ;
}
//write to the server
write(s,buffer,size);
//get response from the server
size=read(s,buffer,1024);
write(1,buffer,size);
}
outfile.close();
}
It's a bit hard to follow because of your variable names, but it looks like your client is working under the assumption that your server will send back a response for every chunk of data received, which isn't the case. You server doesn't appear to have changed the accepted socket to non-blocking, so it's going to block on the read call until there is some data to read (it's never going to get 0)...
Are you sure it's failing before this point? Do you have some sample output?
Aso, in your call to accept, you pass addrlen...
int addrlen = sizeof(struct sockaddr);
I think this should be:
int addrlen = sizeof(struct sockaddr_in); /* sizeof(client_addr) */