Как создать TCP-сокет для подключения с помощью C к предопределенному порту
Вопрос
У меня очень простой вопрос.Я хочу проверить, используется ли конкретный порт в данный момент или нет.Для этого я хочу привязать сокет TCP к порту: если в соединении отказано, это означает, что порт используется, а если нет, то это означает, что порт свободен.
Может кто-нибудь сказать мне, как я могу написать код сокета TCP на C?Я на платформе Solaris.
Я знаю, что это очень просто.Но я ценю вашу помощь.Заранее спасибо.
Решение
Вызов функции привязки вернет -1 в случае ошибки.Это включает в себя случай, когда адрес уже используется.
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 12345
int main()
{
struct sockaddr_in addr;
int fd;
fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd == -1)
{
printf("Error opening socket\n");
return -1;
}
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = 0;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_family = AF_INET;
if(bind(fd, (struct sockaddr *)&addr,sizeof(struct sockaddr_in) ) == -1)
{
printf("Error binding socket\n");
return -1;
}
printf("Successfully bound to port %u\n", PORT);
}
Другие советы
Это немного зависит от того, что именно вы пытаетесь проверить.
С использованием bind()
способ, предложенный joelc, сообщит вам, открыт ли порт любой интерфейс на вашем компьютере.Хотя для большей тщательности вам следует проверять не только возвращаемое значение из bind()
, но и проверка errno == EADDRINUSE
.
то есть.(модификация кода joelc)
if(bind(socket, (struct sockaddr *)&sin,sizeof(struct sockaddr_in) ) == -1)
{
if( errno == EADDRINUSE )
{
// handle port already open case
}
else
{
// handle other errors
}
}
Изменив адрес, используемый в строке:например.
sin.sin_addr.s_addr = inet_addr("192.168.1.1");
... вы можете проверить, доступен ли порт на определенном интерфейсе.
Имейте в виду, однако, что это не идеальный тест состояния порта.Если другой процесс открыл порт и был завершен до того, как он корректно закрыл порт (т.перед звонком close()
на розетке), то вы обычно получите то же самое EADDRINUSE
ошибка.(в зависимости от того, установлена ли в сокете опция SO_REUSEADDR)
(Примечание:если ваше тестовое приложение не работает с достаточными привилегиями, вы не сможете привязать() к любым портам ниже 1024)
Как предложил Anonymous, вы также можете взглянуть на netstat
.Это даст вам всю ту же информацию, которую вы можете получить, неоднократно звоня bind()
гораздо быстрее и без каких-либо побочных эффектов (например, ему не нужно фактически привязываться к портам, что сделало бы их непригодными для использования другими процессами).Просто звоню netstat -a --numeric-ports -t
и анализ результатов должен дать вам все, что вам нужно.
Однако комментарий к предложению moogs: вызов telnet на каждом порту сообщит вам только о том, прослушивает ли сокет этот порт, а не о том, открыт ли он на самом деле.
Вы просто хотите проверить, используется ли конкретный порт в данный момент?(и на самом деле не нужно делать программу).Если да, вы можете использовать telnet:
хост-порт телнета
Если соединение не удалось, оно не используется.Если он подключается и ждет вашего ввода, значит, он используется :)
Возможно, вы захотите посмотреть исходный код netstat.Я считаю, что в Solaris также есть netstat.