1. 程式人生 > >使用C寫socket收發UDP包,併發送UDP包到syslog中

使用C寫socket收發UDP包,併發送UDP包到syslog中

一、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