使用C寫socket收發UDP包,併發送UDP包到syslog中
阿新 • • 發佈:2019-01-24
一、UDP相關程式碼
在main函式中,先建立了一個執行緒來做UDP伺服器,然後建立socket向UDP伺服器傳送和接收資料,最終直接使用給定的ip和埠號,向搭建好的rsyslog伺服器傳送資料,可以看到資料。為了省事,所有的東西都在一個檔案中寫完了,包括UDP伺服器,UDP客戶端。
程式碼如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <unistd.h> #define UDP_TEST_PORT 2234 #define UDP_SERVER_IP "127.0.0.1" #define MAX_LINE 1024 /********************************************************************** * 功能描述:向給定ip和埠號傳送udp字串 * 輸入引數: char *ip:ip地址 * int port:埠號 * char* str:傳送的字串 * 輸出引數:無 * 返 回 值: int:傳送結果 * 其它說明:無 ***********************************************************************/ int send_udp_str(char *ip, int port, char* str) { int ret = 0; if (str == NULL) { ret = -1; return ret; } struct sockaddr_in server; int sockfd = 0; int server_len = sizeof(struct sockaddr_in); /* setup a socket,attention: must be SOCK_DGRAM */ if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); ret = -1; return ret; } /*complete the struct: sockaddr_in*/ bzero(&server, sizeof(server)); server.sin_family = AF_INET; server.sin_port = htons(port); server.sin_addr.s_addr = inet_addr(ip); /* send the string to server*/ if (sendto(sockfd, str, strlen(str), 0, (struct sockaddr *) &server, server_len) < 0) { printf("sendto error\n"); ret = -2; } close(sockfd); return ret; } /********************************************************************** * 功能描述:接收udp字串 * 輸入引數: int sockfd:fd struct sockaddr_in server * char* buf:接收的字串儲存空間,需要先分配好記憶體,如 char buf[1024]; * 輸出引數:無 * 返 回 值: int:結果 * 其它說明:無 ***********************************************************************/ int recv_udp_str_by_fd(int sockfd, struct sockaddr_in server, char* buf) { int ret = 0; if (buf == NULL) { ret = -1; return ret; } memset(buf, 0, sizeof(buf)); int len = 0; int server_len = sizeof(struct sockaddr_in); /* recieve the string from server*/ len = recvfrom(sockfd, buf, 1024, 0, (struct sockaddr *) &server, &server_len); if (len < 0) { printf("recvfrom error\n"); ret = -1; return ret; } // printf("Received len = %d \n", len); return ret; } /********************************************************************** * 功能描述:傳送udp字串 * 輸入引數: int sockfd:fd struct sockaddr_in server * char* str:傳送的字串 * 輸出引數:無 * 返 回 值: int:結果 * 其它說明:無 ***********************************************************************/ int send_udp_str_by_fd(int sockfd, struct sockaddr_in server, char* str) { int ret = 0; if (str == NULL) { ret = -1; return ret; } int len = 0; int server_len = sizeof(struct sockaddr_in); /* send the string to server*/ if (sendto(sockfd, str, strlen(str), 0, (struct sockaddr *) &server, server_len) < 0) { printf("sendto error\n"); ret = -1; } return ret; } /********************************************************************** * 功能描述:開啟一個UDP服務端 * 輸入引數: char *ip:ip地址 * int port:埠號 * 輸出引數:無 * 返 回 值: int:結果 * 其它說明:無 ***********************************************************************/ int UDP_Server_main(char* ip, int port) { //建立套接字 int sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { perror("socket"); // exit(1); return -1; } //將套接字與ip地址和埠號進行繫結 struct sockaddr_in local; local.sin_family = AF_INET; local.sin_port = htons(port); local.sin_addr.s_addr = inet_addr(ip); if (bind(sock, (struct sockaddr*) &local, sizeof(local)) < 0) { perror("bind"); // exit(2); return -2; } char buf[1024]; struct sockaddr_in client; socklen_t len = sizeof(client); char* msg = "Have a goog day"; char msg_back[1024]; while (1) { //讀取資料 int r = recvfrom(sock, buf, sizeof(buf) - 1, 0, (struct sockaddr*) &client, &len); if (r < 0) { perror("recvfrom"); // exit(3); } else { buf[r] = 0; printf("[%s : %d]# %s\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port), buf); sprintf(msg_back, "%s: %s", msg, buf); //回送資料 if (sendto(sock, msg_back, strlen(msg_back), 0, (struct sockaddr*) &client, len) < 0) { perror("sendto"); // exit(4); } if (strcmp(buf, "end") == 0) { break; } } } printf("receive end from [%s : %d]\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port)); close(sock); return 0; } // 開啟UDPServer執行緒的函式,注意配置的ip和port與客戶端一致 int UDP_Server_main_thread() { printf("UDP_Server_main_thread begin\n"); int ret = UDP_Server_main(UDP_SERVER_IP, UDP_TEST_PORT); printf("UDP_Server_main_thread end ret = %d\n", ret); return ret; } int main(int argC, char* arg[]) { int ret = 0; char *ipAddr = UDP_SERVER_IP; int port = UDP_TEST_PORT; char sendStr[MAX_LINE] = {0}; //預設傳送串 char buf[MAX_LINE] = {0}; //接收緩衝區 pthread_t tid; int err; //----------------建立UDP服務端執行緒---------------- err = pthread_create(&tid, NULL, UDP_Server_main_thread, NULL); if (err != 0) { perror(" fail to create thread "); return -1; } sleep(1); // ----------------新建socket,傳送UDP包到服務端執行緒---------------- struct sockaddr_in server; /*complete the struct: sockaddr_in*/ bzero(&server, sizeof(server)); server.sin_family = AF_INET; server.sin_port = htons(port); server.sin_addr.s_addr = inet_addr(ipAddr); int sockfd = 0; /* setup a socket,attention: must be SOCK_DGRAM */ if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); err = -1; return err; } int count = 1; while (1) { sprintf(sendStr, "client-%d|aaa", count); send_udp_str_by_fd(sockfd, server, sendStr); recv_udp_str_by_fd(sockfd, server, buf); printf("Receive from server: %s\n", buf); count +=10; if(count > 100) break; } send_udp_str(ipAddr, port, "aaaaaatest_send"); send_udp_str(ipAddr, port, "bbbbb"); send_udp_str(ipAddr, port, "end"); pthread_join(tid, NULL); // -------------傳送UDP包到syslog服務端---------------- ipAddr = "192.168.3.39"; port = 514; char tmpStr[4096]; int count1 = 1; while(count1 <= 10) { sprintf(tmpStr, "hahaha,to syslog-%d", count1); ret = send_udp_str(ipAddr, port, tmpStr); printf("count = %d; ret = %d\n", count1, ret); sleep(1); count1++; } return 0; }
二、Ubuntu的rsyslog伺服器搭建過程:
1 安裝rsyslog
$ sudo apt-get install rsyslog
直接一步步安裝就好
2 修改配置檔案,開啟接收514埠資料
$ sudo vim /etc/rsyslog.conf
修改內容
先找到514埠相關內容,然後取消註釋(刪除前面的#),改為如下:
# provides UDP syslog reception module(load="imudp") input(type="imudp" port="514") # provides TCP syslog reception module(load="imtcp") input(type="imtcp" port="514")
檢視結果:
$ sudo netstat -tulpn | grep rsyslog tcp 0 0 0.0.0.0:514 0.0.0.0:* LISTEN 2786/rsyslogd tcp6 0 0 :::514 :::* LISTEN 2786/rsyslogd udp 0 0 0.0.0.0:514 0.0.0.0:* 2786/rsyslogd udp6 0 0 :::514 :::* 2786/rsyslogd
可以看到tcp和udp的514埠都打開了。
3 重啟rsyslog服務
$ sudo service rsyslog restart
4 修改啟動配置檔案
$ sudo vim /etc/default/rsyslog
改為如下:
# Options for rsyslogd
# -x disables DNS lookups for remote messages
# See rsyslogd(8) for more details
RSYSLOGD_OPTIONS="-r"
5 檢視結果
$ tail -f /var/log/syslog
執行UDP程式,可以看到結果:
$ tail -f /var/log/syslog
May 24 15:56:26 192.168.3.51 hahaha,to syslog-1
May 24 15:56:27 192.168.3.51 hahaha,to syslog-2
May 24 15:56:28 192.168.3.51 hahaha,to syslog-3
May 24 15:56:29 192.168.3.51 hahaha,to syslog-4
May 24 15:56:30 192.168.3.51 hahaha,to syslog-5
May 24 15:56:31 192.168.3.51 hahaha,to syslog-6
May 24 15:56:32 192.168.3.51 hahaha,to syslog-7
May 24 15:56:33 192.168.3.51 hahaha,to syslog-8
May 24 15:56:34 192.168.3.51 hahaha,to syslog-9
May 24 15:56:35 192.168.3.51 hahaha,to syslog-10
UDP參考:http://velep.com/archives/934.html