This is my code which can run CentOS and Windows just fixing some headers.
#define _WIN32_WINNT 0x0501
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
/*
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
*/
int main()
{
int sock;
int ret = 0;
int port= 12345;
struct sockaddr_in addr;
char buf[1024];
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock<0){
printf("socket() ret = %d : %s\n",ret,strerror(errno));
return ret;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
if(ret<0){
printf("bind() ret = %d errno =%d : %s\n",ret,errno,strerror(errno));
return ret;
}
printf("############# Binding port %d type Enter to stop \t",port);
fgets(buf,sizeof(buf),stdin);
return 0;
}
When I tried to bind same port by this program with runing tow process, there must be the messages that Address already in use like below.
[The first proc#centOS ]
$ ./udp
############# Binding port 12345 type Enter to stop
[The second proc#centOS]
$ ./udp
bind() ret = -1 errno =98 : Address already in use
$
However when I do same thing with same code on windows, message is different.
[The first proc#windows]
C:\ >udp
############# Binding port 12345 type Enter to stop
[The second proc#windows]
C:\ >udp
bind() ret = -1 errno =34 : Result too large
C:\ >
How can I get Address already in use on Windows?
I don't think you should use errno on windows for sockets code. You could try to use WSAGetLastError which returns WSAEADDRINUSE.
The MSDN page for errno suggests EADDRINUSE is not supported for errno.
I think you should devise a scheme where you have a my_errno function that depending on the platform uses errno or WSAGetLastError.
printf("socket() ret = %d : %s\n",ret,strerror(errno));
There may be a subtle issue with this call. The order of argument evaluation is unspecified and strerror itself can change errno, which means it has side-effects. You should print errno separately, before doing anything else.
Like cnicular said, you have to use WSAGetLastError() on Windows, not errno. To get a text message for a socket error code, you can use FormatMessage().
To answer your question, if you want to find out who is using the port, you can use the command-line netstat tool, or programmably using GetTcpTable2().
Related
From online resource, they said that if epoll listening on file descriptors using default mode(level trigger), when the fd(file descriptor) is ready to read and the buffer data associated with fd not fully consumed, epoll will continue to trigger until all data is consumed, however, when I test with epoll(LT mode) listening on udp socket, when multiple characters comes epoll only trigger once.
the process like below:
step 1: create epoll, udp socket fd, then make epoll listening on socket for write event.
step 2: send multiple characters("abc") to the udp socket
step 3: each time epoll triggered, then read 1 character from the udp socket.
I am expecting that epoll trigger three times as udp socket receive 3 characters, but the result is epoll only trigger once.
here is my code:
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define BUFFER_SIZE 512
#define log(fmt, arg...) printf(""fmt, ##arg)
void main(){
int fd1,efd, fds, i, fd;
int ret, addr_len;
struct epoll_event g_event;
struct epoll_event *epoll_events_ptr;
char buffer[BUFFER_SIZE] = {0};
struct sockaddr_in addr1;
fd1 = socket(AF_INET, SOCK_DGRAM, 0);
if (fd1 == -1) {
log("create socket fail \r\n");
return ;
}
addr1.sin_family = AF_INET;
addr1.sin_addr.s_addr = INADDR_ANY;
addr1.sin_port = htons(3500);
addr_len = sizeof(struct sockaddr_in);
if (0 != bind(fd1, (struct sockaddr *)&addr1, sizeof(struct sockaddr_in))) {
log("bind local listening addr fail,errno : %d \r\n", errno);
goto err;
}
efd = epoll_create1(0);
if (efd == -1) {
log("create epoll fail \r\n");
goto err;
}
log("create epoll instance success \r\n");
epoll_events_ptr = (struct epoll_event *)calloc(2, sizeof(struct epoll_event));
if (epoll_events_ptr == NULL) {
log("calloc fail \r\n");
goto err;
}
g_event.data.fd = fd1;
g_event.events = EPOLLIN;
epoll_ctl(efd, EPOLL_CTL_ADD, fd1, &g_event);
while(1) {
fds = epoll_wait(efd, epoll_events_ptr, 2, -1);
for (i = 0; i<fds; i++)
{
if (epoll_events_ptr[i].events & EPOLLIN)
{
ret = recv(fd1, buffer, 1, MSG_DONTWAIT);
if(ret != -1)
log("recv msg : %s \n", buffer);
}
memset(buffer, 0, BUFFER_SIZE);
}
}
err:
close(fd1);
if(epoll_events_ptr)
free(epoll_events_ptr);
return ;
}
enter image description here
You are treating UDP as though it was a streaming protocol, i.e. TCP. It isn't. It is a datagram protocol. If you read a UDP datagram into a buffer that is too small to receive it, the remainder of the datagram is discarded. Not left in the buffer for next time.
Reading one character at a time is therefore pointless in UDP, not to mention extremely inefficient in any protocol.
NB You don't need the memset(), and this:
log("recv msg : %s \n", buffer);
is invalid. It should be:
log("recv msg : %.*s \n", ret, buffer);
You can't assume the received data is null-terminated.
I like using systemd-activate(8) for testing socket-activated daemons during development,
however, it seems it only listens for TCP connections:
% /usr/lib/systemd/systemd-activate -l 5700 ./prog
Listening on [::]:5700 as 3.
% netstat -nl |grep 5700
tcp6 0 0 :::5700 :::* LISTEN
I am using a program that handles datagrams (UDP). How can I make systemd-activate listen on a UDP port? Or is there a
simple way to do this using other tools, without going to the trouble of crafting and installing a systemd unit file?
This was recently added to systemd-activate: https://github.com/systemd/systemd/pull/2411, and will be part of systemd-229 when it is released.
I'm not sure that there is a way to do it with systemd-activate.
You may want to employ some .service unit file and a .socket unit file with dependencies. In a .socket unit you will describe ListenDatagram= option. See here for more details.
I ended up writing a simple C program to do this; code below (public domain).
The usage is:
./a.out <port-number> <prog> [<arg1> ...]
The program opens a UDP socket on <port-number>, sets the environment variables that systemd socket-activated daemons expect, then executes <prog> with whatever arguments follow.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
int main(int argc, char **argv) {
if (argc < 2) {
printf("no port specified\n");
return -1;
}
if (argc < 3) {
printf("no program specified\n");
return -1;
}
uint16_t port = htons((uint16_t) strtoul(argv[1], NULL, 10));
if (port == 0 || errno) {
printf("failed to parse port: %s\n", argv[1]);
return -1;
}
/* create datagram socket */
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
printf("failed to open socket; errno: %d\n", errno);
return -1;
}
struct sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_port = port;
sa.sin_addr.s_addr = INADDR_ANY;
/* bind socket to port */
int r = bind(fd, (struct sockaddr *) &sa, sizeof(struct sockaddr_in));
if (r < 0) {
printf("bind failed; errno: %d\n", errno);
return -1;
}
/* execute subprocess */
setenv("LISTEN_FDS", "1", 0);
execvp(argv[2], argv + 2);
}
i'm trying to create server with TCP IP protocol
But it doesn't accept connection, or may be because of listen
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <netdb.h>
#include <strings.h>
#include <arpa/inet.h>
#include <unistd.h>
void error(char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd,newsockfd,num_port,serveur_T;
socklen_t client_T;
char buffer[200];
struct sockaddr_in adr_serveur, adr_client;
int n;
if (argc < 2)
{
fprintf(stderr, "nombre d'arguments est insuffisant\n");
exit(1);
}
sockfd=socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
error("erreur de creation de socket");
}
serveur_T=sizeof(adr_serveur);
bzero((char*)&adr_serveur, serveur_T);
num_port=atoi(argv[1]);
adr_serveur.sin_family=AF_INET;
adr_serveur.sin_addr.s_addr=INADDR_ANY;
adr_serveur.sin_port=htons(num_port);
serveur_T=sizeof(adr_serveur);
if (bind ( sockfd,(struct sockaddr *) &adr_serveur,serveur_T)<0)
{
error(" Erreur de binding");
}
listen (sockfd,5);
client_T= sizeof(adr_client);
newsockfd= accept(sockfd,(struct sockaddr *) &adr_client,&client_T);
if ( newsockfd<0)
{
error("Erreur socket accept");
}
bzero(buffer, 200);
return 0;}
When I execute server I got this error
Erreur socket accept: Operation not supported
Second question: Can I use an IRC client and connect it to my server ? In my school we have Linux servers so I'm wondering if I can use them as a hostname ?
Thanks
i'm trying to create server with TCP IP protocol
You have created a SOCK_DGRAM (UDP) socket, not a SOCK_STREAM (TCP) socket. You cannot call listen() or accept() on a UDP socket, only on a TCP socket. listen() is reporting an EOPNOTSUPP error:
listen(2)
EOPNOTSUPP
The socket is not of a type that supports the listen() operation.
You are ignoring that error, and then accept() is reporting the same error:
accept(2)
EOPNOTSUPP
The referenced socket is not of type SOCK_STREAM.
There are no connections in UDP, so there is nothing to accept. Once you have bound a UDP socket to a port, you can start calling recvfrom() and sendto() on it.
In order to connect an IRC client to this server code, you need to change the socket type to SOCK_STREAM. IRC runs on TCP, not on UDP.
i wrote a client application in c using the posix sockets api on linux that sends information to a server, which then gets printed to the servers terminal window. If the server is on the same machine as the client and the client sends to the loopback or to its own IP address then all is good. However, if the server is running on another machine, then sendto returns an "invalid argument" error.
Here is the code for the client application:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include "utils.h" // for 'errexit()'
#define PEER_PORT 54321
#define BUFFSIZE 100
#define local_net_ip "192.168.0.10"
int main( int argc, char *argv[] )
{
int clientfd;
clientfd = socket( AF_INET, SOCK_DGRAM, 0 );
if( clientfd == -1 )
errexit( "socket()" );
struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons( PEER_PORT );
if( inet_pton( AF_INET, local_net_ip, (void *) &(servaddr.sin_addr) ) == -1 )
errexit( "inet_pton()" );
char addrStr[ INET_ADDRSTRLEN ];
inet_ntop( servaddr.sin_family, &(servaddr.sin_addr), addrStr, INET_ADDRSTRLEN );
printf("Server IPv4 addr: [ %s ]\n", addrStr);
char buff[ BUFFSIZE ];
int writebytes;
for( ;; ) {
printf( "Enter text: ");
fgets( buff, BUFFSIZE, stdin );
writebytes = sendto( clientfd, buff, BUFFSIZE, 0, (struct sockaddr *) &servaddr, sizeof( struct sockaddr_in ) );
if( writebytes == -1 )
errexit( "sendto()" );
}
exit( EXIT_SUCCESS );
}
I would greatly appreciate any information as to why the application won't send to another computer! Thanks in advance!!
clientfd = socket( AF_INET, SOCK_DGRAM, 0 );
You are creating a socket with protocol 0, e.g. IP. But later you use and IP:Port as a target. You probably wanted to use an UDP socket here (proto 17).
The following works without error on OSX 10.6, but fails in the iphone simulator using SDK 4.1
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/tcp.h>
#include <sys/un.h>
#include <string.h>
int main(void) {
int sock = socket(AF_UNIX, SOCK_DGRAM, 0);
struct sockaddr_un sock_addr;
memset(&sock_addr, 0, sizeof(struct sockaddr_un));
sock_addr.sun_family = AF_UNIX;
strcpy(sock_addr.sun_path, "/tmp/sock");
int err = bind(sock, (struct sockaddr*)&sock_addr, sizeof(struct sockaddr_un));
if(err == -1) {
perror("bind: ");
}
}
Error is "Address family not supported by protocol family"
Any ideas?
You really need to check sock already - most likely, the socket creation is what failed already.
My guess is that AF_UNIX/SOCK_DGRAM is not supported; try SOCK_STREAM instead.