I am new to C language, and when I used c to write a socket program, I encountered a problem.
I want to implement two-way communication between two computers (Linux and Simulink). In Linux, I need to implement a connection-based UDP client and server. And for other needs, I divided the process of creating UDP communication into four parts: creating the sender socket, server binding process, sending data and accepting data.
The code is compiled successfully. During the run, the value can be successfully sent to Simulink, but it is blocked on the 'recv()' function. I used Wireshark to view the data packets of the computer where Simulink is located. The data packets of this computer are normal. In other words, the socket in Linux received the datagram, but my program could not read it.
The code in Linux is as below:
void check_comm_error(int ret);// just for check error
void sendsock_creat(); //creat socket and server ip address
void sendsock_send(void* send_buf); //call send function and send data
void recvsock_creat(); called by sendsock_creat function
void recvsock_recv(); just for receieve data
int client_fd; //定义套接字描述符
double senddata[1] = {10};
double recvdata[1];
struct sockaddr_in local_addr;//定义本地地址 <netinet/in.h>
void sendsock_creat()
{
int check_ret = 0;//定义操作返回值,以传给check_comm_error函数
struct sockaddr_in server_addr;//定义服务器地址 <netinet/in.h>
int ser_addr_len;//定义服务端地址长度
client_fd = socket(AF_INET, SOCK_DGRAM, 0); //创建客户端套接字
check_ret = client_fd;
check_comm_error(check_ret);//判断是否出错
recvsock_creat();//Need to run the bind function before connect function
memset(&server_addr, 0, sizeof(server_addr)); //清空服务器地址结构体
server_addr.sin_family = AF_INET; //定义地址中的地址类型
server_addr.sin_addr.s_addr = inet_addr(SERVER_ADDR);//给出服务端的ip地址
server_addr.sin_port = htons(SERVER_PORT); //
check_ret=connect(client_fd, (struct sockaddr*)&server_addr,
sizeof(server_addr)); //连接服务端
check_comm_error(check_ret);//判断是否出错
}
void sendsock_send(void* send_buf)
{
//void* send_buf 为待发送的数据缓冲区
int check_ret = 0;
check_ret = send(client_fd, send_buf, sizeof(send_buf), 0);
check_comm_error(check_ret);
}
void check_comm_error(int ret)
{
if(ret < 0)
{
perror("create socket fail!\n");
exit(1);
}
}
void recvsock_creat()
{
int check_ret = 0;//定义操作返回值,以传给check_comm_error函数
int recv_flag; //接受标志
int ser_addr_len;//定义本地地址长度
memset(&local_addr, 0, sizeof(struct sockaddr_in));
local_addr.sin_family=AF_INET;//bind to a local port
local_addr.sin_addr.s_addr=htonl(INADDR_ANY);
local_addr.sin_port=htons(LOCAL_PORT);
check_ret = bind(client_fd,(struct sockaddr *)&local_addr, sizeof(struct
sockaddr_in));
check_comm_error(check_ret);
recv(client_fd, recvdata, sizeof(recvdata), 0); //This function can get
the right value
printf("recv from simulink %f \n", recvdata[0]);
}
void recvsock_recv()
{
int recv_flag;
int addr_len;
recv_flag = recv(client_fd, recvdata, sizeof(recvdata),0);
}
int main()
{
sendsock_creat();
sendsock_send((double *)senddata);
recvsock_recv();
printf("recv from matlab %f .\n",recvdata[0]);
return 0;
}
Because the program has been compiled, the head file part is definitely no problem, So I ignore the include that part.
Related
I have an application installed locally (not developed by me), which broadcasts UDP packets every second.
Reading the packets from my application (developed in C++ in Windows) which also is locally installed, works fine.
WSADATA data;
WORD version = MAKEWORD(2, 2);
int wsOK = WSAStartup(version, &data);
SOCKET serverIn = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
sockaddr_in serverHint;
serverHint.sin_addr.S_un.S_addr = INADDR_ANY;
serverHint.sin_family = AF_INET;
serverHint.sin_port = htons(UDP_RECEIVE_PORT);
bind(serverIn, (sockaddr*)&serverHint, sizeof(serverHint));
sockaddr_in client;
int clientSize = sizeof(client);
int RECIEVE_BUFFER_SIZE = 65507;
char* recieveBuffer = new char[RECIEVE_BUFFER_SIZE];
while(updating)
{
int bytesIn = recvfrom(serverIn, recieveBuffer, RECIEVE_BUFFER_SIZE, 0, (sockaddr*)&client, &clientSize);
}
closesocket(serverIn);
WSACleanup();
But I recently noticed while I was testing some code, while my app was running, that the bind(...)
function returned an error code of 10048 (WSAEADDRINUSE). Hence, it seems the first client bound to listen for the UDP packets is the only one who can listen, and the other clients is unable to read the broadcasted UDP packets.
So then I added the SO_REUSEADDR option before calling the bind(...) function to be able to bind successfully to the socket:
BOOL bOptVal = TRUE;
int bOptLen = sizeof(BOOL);
setsockopt((SOCKET)serverIn, SOL_SOCKET, SO_REUSEADDR, (char*)&bOptVal, bOptLen);
That works, but the recvfrom(...) function then does not recieve any data at all! I guess it waits for the other client to close its socket.
Next solution is to initialize the socket with SOCK_RAW instead.
The above option SO_REUSEADDR is now not needed, and remove it:
SOCKET serverIn = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
This works, I can read the data now! Though, Windows now requires the adminstrator rights for my application. Also I do recieve the UDP information in the data which I do not need.
Is there any better method to do this without requiring administrator rights, any possibility to discard the header information in the buffer?
Below is a little program I wrote to demonstrate that IPv4 UDP broadcast can and does work as expected under Windows (i.e. without requiring raw-sockets or Administrator privileges).
Run it with the command line argument "server" and it will send out one broadcast UDP packet per second.
Then also run several more instances of the same program, with no command line arguments, to receive the UDP packets and print a line of text to stdout whenever they do. The expected behavior should look like this:
As for why it's not working for you -- one possible guess is that your UDP-packet-sending program is actually sending out unicast UDP packets rather than broadcast. If that's the case, then I would expect that only one client program would receive packets (even if multiple clients are bound to the same port). A network trace tool like Wireshark might be able to help you determine if the UDP packets being sent are broadcast or unicast.
Anyway, here's the code:
#include <stdio.h>
#include <ws2tcpip.h>
#pragma comment(lib,"WS2_32")
static int BindUDPSocket(SOCKET sock, unsigned short port, bool allowPortSharing)
{
if (sock == INVALID_SOCKET) return -1;
if (allowPortSharing)
{
const BOOL trueValue = true;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &trueValue, sizeof(trueValue)) < 0) return -1;
}
struct sockaddr_in bindAddr; memset(&bindAddr, 0, sizeof(bindAddr));
bindAddr.sin_family = AF_INET;
bindAddr.sin_addr.s_addr = INADDR_ANY; // aka 0.0.0.0
bindAddr.sin_port = htons(port);
return bind(sock, (struct sockaddr *) &bindAddr, sizeof(bindAddr));
}
int main(int argc, char ** argv)
{
WSADATA data;
WORD version = MAKEWORD(2, 2);
(void) WSAStartup(version, &data);
const unsigned short TEST_PORT = 12345;
SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock<0) {printf("socket() failed\n"); exit(10);}
if ((argc > 1)&&(strcmp(argv[1], "server") == 0))
{
if (BindUDPSocket(sock, 0, false)<0) {printf("BindUDPSocket() failed for server\n"); exit(10);}
const BOOL allowBroadcast = true;
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char *) &allowBroadcast, sizeof(allowBroadcast)) < 0)
{
printf("setsockopt(SO_BROADCAST) failed\n");
exit(10);
}
const char buf[] = {0x01, 0x02, 0x03, 0x04}; // dummy data
struct sockaddr_in toAddr; memset(&toAddr, 0, sizeof(toAddr));
toAddr.sin_family = AF_INET;
toAddr.sin_addr.s_addr = INADDR_BROADCAST; // aka 255.255.255.255
toAddr.sin_port = htons(TEST_PORT);
printf("Sending outgoing broadcast UDP sockets on port %u, once per second\n", TEST_PORT);
while(true)
{
if (sendto(sock, buf, sizeof(buf), 0, (const sockaddr *) &toAddr, sizeof(toAddr)) == sizeof(buf))
{
printf("Sent %zu bytes of broadcast UDP data\n", sizeof(buf));
}
else printf("sendto() failed!\n");
Sleep(1000); // wait 1 second
}
}
else
{
if (BindUDPSocket(sock, TEST_PORT, true)<0) {printf("BindUDPSocket() failed for client\n"); exit(10);}
printf("Waiting to receive incoming broadcast UDP sockets on port %u\n", TEST_PORT);
while(true)
{
char buf[1024];
const int ret = recv(sock, buf, sizeof(buf), 0L);
printf("Received %i bytes of incoming UDP data\n", ret);
}
}
}
TCP socket demultiplexing at the server port (which listens for multiple TCP connections) happens with a separate socket descriptor created for each established TCP connection(though the accept() call) and the socket descriptor is tightly coupled with tuple [source IP address, source port, destination IP address, destination IP address]. Over this established connection we can use the high layer application protocols like HTTP, FTP, SSH etc.,
But in case of UDP there is no session/connection established between the peers. The server waiting at the particular port receives the message from any client. The client's IP address and port number is known after receiving the message(populated in the socket address structure). From the address structure the messages can be demultiplexed and given to respective applications.
Over the server port, If I want to establish a connected session over UDP[like the tuple mentioned in case of TCP] so that communication between the server and client (between particular port on server and client) can be demultiplexed before receiving the message(without inferring the same from socket address structure) so that the higher layer protocols can work like on TCP (ofcourse higher layer protocols like DTLS taking care of the reliability)
Below is the code for UDP server(leveraging the connect() API to keep the UDP socket connected) and UDP client
// server program for udp connection
#include <stdio.h>
#include <strings.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PORT 5000
#define MAXLINE 1000
//logical thread num
static unsigned int threadnum = 0;
struct pass_info {
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
unsigned int threadnum;
};
char *message = "Hello Client";
void* connection_handle(void *info) {
int fd = 0;
char buffer[100];
int n = 0;
const int on = 1;
struct pass_info *pinfo = (struct pass_info*) info;
printf("Executing thread : %d\n", pinfo->threadnum);
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
printf("Error socket!!!");
return;
}
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &on, (socklen_t) sizeof(on));
bind(fd, (const struct sockaddr *) &pinfo->server_addr, sizeof(struct sockaddr_in));
connect(fd, (struct sockaddr *) &pinfo->client_addr, sizeof(struct sockaddr_in));
while(1)
{
n = recv(fd, buffer, sizeof(buffer), 0);
if (n < 0)
{
printf("receive failed! in thread : %d", pinfo->threadnum);
break;
}
buffer[n] = '\0';
printf("Thread num %d: Recv message - %s\n", pinfo->threadnum, buffer);
n = send(fd, message, sizeof(message), 0);
if (n < 0)
{
printf("send failed! in thread : %d", pinfo->threadnum);
break;
}
}
free(info);
return NULL;
}
int main()
{
char buffer[100];
int listenfd, len, sockfd;
const int on = 1;
struct sockaddr_in servaddr, cliaddr;
bzero(&servaddr, sizeof(servaddr));
struct pass_info *info;
pthread_t tid;
// Create a UDP Socket
listenfd = socket(AF_INET, SOCK_DGRAM, 0);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT);
servaddr.sin_family = AF_INET;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const void*) &on, (socklen_t) sizeof(on));
// bind server address to socket descriptor
bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
while (1)
{
//receive the datagram
len = sizeof(cliaddr);
int n = recvfrom(listenfd, buffer, sizeof(buffer),
0, (struct sockaddr*)&cliaddr,&len); //receive message from server
buffer[n] = '\0';
printf("Main thread: Recv message - %s\n", buffer);
n = sendto(listenfd, message, MAXLINE, 0, (struct sockaddr*)&cliaddr, sizeof(cliaddr));
info = (struct pass_info*) malloc (sizeof(struct pass_info));
memcpy(&info->server_addr, &servaddr, sizeof(struct sockaddr_in));
memcpy(&info->client_addr, &cliaddr, sizeof(struct sockaddr_in));
threadnum++;
info->threadnum = threadnum;
if (pthread_create(&tid, NULL, connection_handle, info) != 0) {
perror("pthread_create");
exit(-1);
}
}
}
// udp client program
#include <stdio.h>
#include <strings.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#include<stdlib.h>
#define PORT 5000
#define MAXLINE 1000
int main()
{
char buffer[100];
char *message = "Hello Server";
int sockfd, n;
struct sockaddr_in servaddr, cliaddr;
int len = 0;
// clear servaddr
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servaddr.sin_port = htons(PORT);
servaddr.sin_family = AF_INET;
// create datagram socket
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
while(1)
{
sleep(3);
sendto(sockfd, message, MAXLINE, 0, (struct sockaddr*)&servaddr, sizeof(servaddr));
// waiting for response
recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&cliaddr, &len);
puts(buffer);
}
}
Queries:
Whether this would be the right way to do de-multiplexing at the UDP socket level
The server listens for any UDP packets from the client. once it receives a message, new socket descriptor is created and the connect() API is called so that the client's IP address, port is registered with this newly created socket descriptor and from here on newly created socket descriptor will used to send and receive messages to the particular client's IP address and port. Whether it is a fool proof method
Are there any other well known methods to use the higher layer protocols(protocols supporting reliability like DTLS) over UDP
I'm new in socket programming.
My program creates two clients that write to a server, this server reads data using threads and then prints them. I would like to send all this data to another client when it makes a request. Have I to create another socket or is it possible to use the same used before?
Here is my code.
Thanks.
Server.c
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include <arpa/inet.h>
#include <fcntl.h> // for open
#include <unistd.h> // for close
#include<pthread.h>
struct message { //dichiarazione struct
time_t timestamp;
char g; //process identifier
int x;
};
struct message client_message[10000];
int q=0;
static void * socketThread(void *arg)
{
int newSocket = *((int *)arg);
while(read(newSocket , &client_message[q] , sizeof(client_message))!=0) {
printf("message %d %d %ld\n",client_message[q].x,client_message[q].g,client_message[q].timestamp);
fflush(stdout);
sleep(1);
q++;
}
pthread_exit(NULL);
}
int main(){
int serverSocket, newSocket;
struct sockaddr_in serverAddr;
struct sockaddr_storage serverStorage;
socklen_t addr_size;
//Create the socket.
serverSocket = socket(AF_UNIX, SOCK_STREAM, 0);
// Configure settings of the server address struct
// Address family = Internet
serverAddr.sin_family = AF_UNIX;
//Set port number, using htons function to use proper byte order
serverAddr.sin_port = htons(55555);
//Set IP address to localhost
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
//INADDR_ANY;
//Set all bits of the padding field to 0
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
//Bind the address struct to the socket
bind(serverSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
//Listen on the socket, with 40 max connection requests queued
if(listen(serverSocket,50)==0)
printf("Listening\n");
else
printf("Error\n");
pthread_t tid[2];
int i = 0;
while(i<2)
{
//Accept call creates a new socket for the incoming connection
addr_size = sizeof serverStorage;
newSocket = accept(serverSocket, (struct sockaddr *) &serverStorage, &addr_size);
//for each client request creates a thread and assign the client request to it to process
//so the main thread can entertain next request
if( pthread_create(&tid[i], NULL, socketThread, &newSocket) != 0 )
printf("Failed to create thread\n");
i++;
}
pthread_join(tid[1], NULL);
pthread_join(tid[0], NULL);
for(i=0;i<50;i++){
printf("%d aaa %d\n",client_message[i].x,client_message[i].g);
}
close(newSocket);
return 0;
}
My situation is as follows:
I have a windows machine running a UDP Multicast server that is broadcasting packets. I wrote a window client that is able to capture these packets without a problem on a separate windows machine that is connected to the network. I ran into a few firewall problems on the windows machines, but worked that out.
Now, I have an ubuntu 12.04 version of the client; however, my program isn't finding these packets. I ran through all the suggestions provided by other stack overflow posts and some google threads:
when I am running my client, netstat -g shows the IP address of the multicast network
I set the rp_filter to 0 using sysctl
I can see the packets when using tcpdump -i wlan0
Added a route (sudo route add -net 224.0.0.0 netmask 224.0.0.0 wlan0)
For step four, this is a wireless connection established over wlan0, so I add the route on wlan0. Similarly, wlan0's rp_filter=0.
Now, for the code. From the print statements and error checking. I am seeing that I am successfully binding, joining the multicast group, creating the buffer, etc... Then it just blocks at the recvfrom() function call.
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <unistd.h>
#include <pthread.h>
#include <fstream>
#pragma warning( disable : 4996 )
#define MAX_PACKETSIZE 100000 // max size of packet (actual packet size is dynamic)
bool IPAddress_StringToAddr(char *szNameOrAddress, struct in_addr *Address);
void Unpack(char* pData);
#define MULTICAST_ADDRESS "239.255.42.99" // IANA, local network
#define PORT_COMMAND 1510
#define PORT_DATA 1511
#define SOCKET_ERROR -1
#define INVALID_SOCKET -1
typedef int SOCKET;
SOCKET DataSocket;
int main(int argc, char* argv[])
{
int retval;
char szMyIPAddress[128] = "";
in_addr MyAddress, MultiCastAddress;
int optval = 0x100000;
int optval_size = 4;
// client address
if(argc>1)
{
strcpy(szMyIPAddress, argv[1]); // specified on command line
IPAddress_StringToAddr(szMyIPAddress, &MyAddress);
}
else
{ printf("usage: ./client [local_ip_address]\n"); return 0; }
MultiCastAddress.s_addr = inet_addr(MULTICAST_ADDRESS);
printf("Client: %s\n", szMyIPAddress);
printf("Multicast Group: %s\n", MULTICAST_ADDRESS);
// create a "Data" socket
printf("Create Socket.\n");
DataSocket = socket(AF_INET, SOCK_DGRAM, 0);
// allow multiple clients on same machine to use address/port
int value = 1;
printf("Set SO_REUSEADDR sockopt.\n");
retval = setsockopt(DataSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&value, sizeof(value));
if (retval == SOCKET_ERROR)
{
close(DataSocket);
return -1;
}
//bind
struct sockaddr_in MySocketAddr;
memset(&MySocketAddr, 0, sizeof(MySocketAddr));
MySocketAddr.sin_family = AF_INET;
MySocketAddr.sin_port = htons(PORT_DATA);
MySocketAddr.sin_addr = MyAddress;
printf("Bind Socket.\n");
if (bind(DataSocket, (struct sockaddr *)&MySocketAddr, sizeof(struct sockaddr)) == SOCKET_ERROR)
{
printf("[PacketClient] bind failed.\n");
return 0;
}
// join multicast group
struct ip_mreq Mreq;
Mreq.imr_multiaddr = MultiCastAddress;
Mreq.imr_interface = MyAddress;
printf("Join multicast group.\n");
retval = setsockopt(DataSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&Mreq, sizeof(Mreq));
if (retval == SOCKET_ERROR)
{
printf("[PacketClient] join failed.\n");
return -1;
}
// create a 1MB buffer
printf("Create 1MB Buffer.\n");
setsockopt(DataSocket, SOL_SOCKET, SO_RCVBUF, (char *)&optval, 4);
getsockopt(DataSocket, SOL_SOCKET, SO_RCVBUF, (char *)&optval, (socklen_t*)&optval_size);
if (optval != 0x100000)
{
printf("[PacketClient] ReceiveBuffer size = %d\n", optval);
}
//listening
printf("Listening...\n");
char szData[20000];
int addr_len = sizeof(struct sockaddr);
sockaddr_in TheirAddress;
while (1)
{
// Block until we receive a datagram from the network (from anyone including ourselves)
int nDataBytesReceived = recvfrom(DataSocket, szData, sizeof(szData), 0, (sockaddr *)&TheirAddress, (socklen_t*)&addr_len);
Unpack(szData);
}
return 0;
}
// convert ipp address string to addr
bool IPAddress_StringToAddr(char *szNameOrAddress, struct in_addr *Address)
{
int retVal;
struct sockaddr_in saGNI;
char hostName[256];
char servInfo[256];
u_short port;
port = 0;
// Set up sockaddr_in structure which is passed to the getnameinfo function
saGNI.sin_family = AF_INET;
saGNI.sin_addr.s_addr = inet_addr(szNameOrAddress);
saGNI.sin_port = htons(port);
// getnameinfo
if ((retVal = getnameinfo((sockaddr *)&saGNI, sizeof(sockaddr), hostName, 256, servInfo, 256, NI_NUMERICSERV)) != 0)
{
printf("[PacketClient] GetHostByAddr failed.\n");
return false;
}
Address->s_addr = saGNI.sin_addr.s_addr;
return true;
}
void Unpack(char* pData)
{
printf("Begin Packet\n-------\n");
}
Any suggestions are appreciated. Here is the question I used as a reference when trying to fix this problem: UDP socket (multicast) not receiving data (Ubuntu)
I paste my answer here instead writing it in comments.
As I understood you have windows machines on both sides, successfully broadcasting udp packets and now you want to replace them with ubuntu machines. And the machines are receiving the packets, but your client isn't notified.
Maybe this will help
SOL_SOCKET is for the socket layer, IPPROTO_IP for the IP layer, etc... For multicast programming, level will always be IPPROTO_IP
Here is the working code for simplified RIPv2 protocol that sends and reives multicast traffic without an problem.
int setup_sender_connection(struct in_addr interface_addr){
//create socket
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock<0){
die("Creating Socket");
}
//set outgoing interface
if(setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &interface_addr, sizeof(interface_addr))<0){
die("Setting outgoing interface");
}
//disable loopback
u_char loop = 0;
if(setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop))<0){
die("Disabling loopback");
}
//allow reusing of port
int reuse = 1;
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0){
die("Allowing reuse");
}
//bind to this port
struct sockaddr_in saddr;
bzero(&saddr, sizeof(struct sockaddr_in));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(520);
saddr.sin_addr = interface_addr;
if(bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in))<0){
die("Binding");
}
return sock;
}
void join_group(int sock, struct in_addr interface_addr){
//join gorup
struct ip_mreq mreq;
bzero(&mreq, sizeof(struct ip_mreq));
mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_IP); /* IP multicast address of group */
mreq.imr_interface = interface_addr; /* local IP address of interface */
if(setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))<0){
die("Joining group");
}
}
void die(char *error){
perror(error);
exit(1);
}
I am new in Unix/Linux networking programming, so I have written server-client program in below.In this code there is one socket between client and server, client requests to server, then server responses from 1 to 100 numbers to client. So my question is how can we do this process with 3 socket( tcp connection) without using thread? ( e.g. First socket runs then second runs then third runs then first again. ) Do you have any suggestion?
Client.c
int main()
{
int sock;
struct sockaddr_in sa;
int ret;
char buf[1024];
int x;
sock = socket (AF_INET, SOCK_STREAM, 0);
bzero (&sa, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(SERVER_PORT);
inet_pton (AF_INET, SERVER_IP, &sa.sin_addr);
ret = connect (sock,
(const struct sockaddr *) &sa,sizeof (sa));
if (ret != 0) {
printf ("connect failed\n");
exit (0);
}
x = 0;
while (x != -1) {
read (sock, buf , sizeof(int));
x = ntohl(*((int *)buf));
if (x != -1)
printf ("int rcvd = %d\n", x);
}
close (sock);
exit (0);
}
Server.c
int main()
{
int list_sock;
int conn_sock;
struct sockaddr_in sa, ca;
socklen_t ca_len;
char buf[1024];
int i;
char ipaddrstr[IPSTRLEN];
list_sock = socket (AF_INET, SOCK_STREAM, 0);
bzero (&sa, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_ANY);
sa.sin_port = htons(SERVER_PORT);
bind (list_sock,(struct sockaddr *) &sa,sizeof(sa));
listen (list_sock, 5);
while (1){
bzero (&ca, sizeof(ca));
ca_len = sizeof(ca); // important to initialize
conn_sock = accept (list_sock,(struct sockaddr *) &ca,&ca_len);
printf ("connection from: ip=%s port=%d \n",inet_ntop(AF_INET, &(ca.sin_addr),
ipaddrstr, IPSTRLEN),ntohs(ca.sin_port));
for (i=0; i<100; ++i){
*((int *)buf) = htonl(i+20);
// we using converting to network byte order
write (conn_sock, buf, sizeof(int));
}
* ((int *)buf) = htonl(-1);
write (conn_sock, buf, sizeof(int));
close (conn_sock);
printf ("server closed connection to client\n");
}
}
I think it best to look at the excellent resource Beej's Guide to Netwokr Programming which goes into detail about this. He also has some good examples which you can use as a starting point and he covers all the major platforms including windows.
Basically you do:
socket()
bind()
listen()
accept()
accept() returns a socket connected to a unique client. Then you'd use select, poll or epoll to determine when data is available on those sockets. I suggest you can look at the man pages for these API's and Beej's guide. It's where I first learned network programming.
Looking at your code, your inner loop is wrong. When you accept a connection, you need to add it to a list or something. Currently, you overwrite it and loose it. You should use (e)poll or select to tell you which has data. You can write to any of them at any time. Again, look at the examples in Beej's guide, they are most helpful.
Maybe it's not exactly what you want,but I think you could try epoll,There is a simple example
typedef struct event_loop
{
int max_event;
int epfd;
}event_loop;
event_loop* create_event_loop()
{
event_loop *ep = malloc(sizeof(event_loop));
ep->max_event = 512;
ep->epfd = epoll_create(512);
return ep;
}
int add_event(event_loop *ep, int fd)
{
epoll_event ee;
ee.data.fd = fd;
ee.event = EPOLLIN | EPOLLPRI;
epoll_ctl(ep->epfd, EPOLL_CTL_ADD, fd, &ee);
}
void event_main(event_loop *ep, int listenfd)
{
epoll_event events[512];
int nfds, i, newfd;
while(1)
{
if(nfds = epoll_wait(ep->epfd, events, 512, -1) == -1)
exit(1);
for(i = 0; i < nfds; i++)
{
if(events[nfds].data.fd == listenfd)
{
newfd = accept(listenfd, NULL, NULL);
add_event(ep, newfd);
}
else
{
//do what you want
}
}
}
}
epoll is a high-efficiency solution,just man epoll get more information