Linux下socket程式設計之UDP簡單實現
阿新 • • 發佈:2019-01-29
本文實現一個簡單的UDP小例子,來說明Linux下socket程式設計之UDP的簡單實現。本文主要包括三個部分:伺服器端的實現,客服端的實現和通訊測試。實現的功能:客服端傳送一條訊息給伺服器端,伺服器端把客服端發來的訊息給顯示出來。
一、伺服器端的實現
1、開啟一個socket使用者伺服器
/* 1、開啟一個socket */
iSocketServerFd = socket(AF_INET, SOCK_DGRAM, 0); // 網路型別為ipv4,連結型別為udp
2、將上面開啟的socket與伺服器進行繫結
3、接收客服端傳送過來的資料/* 2、繫結 */ /* 2.1 設定要繫結的伺服器端 */ tSocketServerAddr.sin_family = AF_INET; // 網路型別為ipv4 tSocketServerAddr.sin_port = htons(SOCKET_PORT); // 設定伺服器埠 tSocketServerAddr.sin_addr.s_addr = htonl(INADDR_ANY); memset(tSocketServerAddr.sin_zero, 0, 8); iSockAddrLen = sizeof(struct sockaddr); /* 2.2 對伺服器端進行繫結 */ iRet = bind(iSocketServerFd, (const struct sockaddr *)&tSocketServerAddr, iSockAddrLen);
/* 3、接收資料 */
iRecvLen = recvfrom(iSocketServerFd, ucRecvBuf, ARRAY_LENGTH, 0,
(struct sockaddr *)&tSocketClientAddr, &iSockAddrLen);
伺服器端實現的完整程式碼如下所示:二、客服端的實現#include <stdio.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <string.h> #include <netinet/in.h> #include <arpa/inet.h> #include <signal.h> #define SOCKET_PORT 1234 // 定義socket繫結的埠 #define LISTEN_BACKLOG 10 // 設定伺服器最大的監聽數量 #define ARRAY_LENGTH 256 // 定義緩衝區的大小 /* * 接收客服端傳送過來的資料,並把它們打印出來 */ int main(void) { int iSocketServerFd; // 定義伺服器端的socket檔案描述符 int iSocketClientFd; // 定義客服端的socket檔案描述符 struct sockaddr_in tSocketServerAddr; struct sockaddr_in tSocketClientAddr; int iSockAddrLen; int iRet; unsigned char ucRecvBuf[ARRAY_LENGTH]; // 定義接收緩衝區 int iRecvLen; signal(SIGCHLD,SIG_IGN); /* 1、開啟一個socket */ iSocketServerFd = socket(AF_INET, SOCK_DGRAM, 0); // 網路型別為ipv4,連結型別為udp if(iSocketServerFd == -1) { printf("socket error!\n"); return -1; } /* 2、繫結 */ /* 2.1 設定要繫結的伺服器端 */ tSocketServerAddr.sin_family = AF_INET; // 網路型別為ipv4 tSocketServerAddr.sin_port = htons(SOCKET_PORT); // 設定伺服器埠 tSocketServerAddr.sin_addr.s_addr = htonl(INADDR_ANY); memset(tSocketServerAddr.sin_zero, 0, 8); iSockAddrLen = sizeof(struct sockaddr); /* 2.2 對伺服器端進行繫結 */ iRet = bind(iSocketServerFd, (const struct sockaddr *)&tSocketServerAddr, iSockAddrLen); if(iRet == -1) { printf("bind error!\n"); return -1; } while(1) { /* 3、接收資料 */ iRecvLen = recvfrom(iSocketServerFd, ucRecvBuf, ARRAY_LENGTH, 0, (struct sockaddr *)&tSocketClientAddr, &iSockAddrLen); if(iRecvLen <= 0) // 失敗 { printf("recvfrom error!\n"); close(iSocketServerFd); return -1; } else // 成功,將接收到的資料打印出來 { ucRecvBuf[iRecvLen] = '\0'; printf("Receive a message from : %s\n", inet_ntoa(tSocketClientAddr.sin_addr)); printf("The message is : %s\n", ucRecvBuf); } } close(iSocketServerFd); return 0; }
客服端的實現總體上來說分為兩種方式:一種是先和伺服器端進行連結然後在進行通訊,另一種是直接進行通訊。
2.1 先連線再通訊
a、開啟一個socket用於客服端
/* 1、開啟一個socket用於客服端 */
iSocketClientFd = socket(AF_INET, SOCK_DGRAM, 0);
b、連線
c、傳送資料/* 2、connect */ /* 2.1 設定連結的伺服器端的基本資訊 */ tSocketServerAddr.sin_family = AF_INET; // 網路型別為ipv4 tSocketServerAddr.sin_port = htons(SOCKET_PORT); // 伺服器端的網路埠 iRet = inet_aton(argv[1], &tSocketServerAddr.sin_addr); // 客服端的ip地址 if(iRet == 0) { printf("server ip is not valid!\n"); return -1; } memset(tSocketServerAddr.sin_zero, 0, 8); iSockAddrLen = sizeof(struct sockaddr); /* 2.2 將伺服器端和客服端連結起來 */ iRet = connect(iSocketClientFd, (const struct sockaddr *)&tSocketServerAddr, iSockAddrLen);
/* 3、將使用者的輸入傳送給伺服器端 */
iSendLen = send(iSocketClientFd, ucSendBuf, strlen(ucSendBuf), 0);
完整的程式碼如下:#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SOCKET_PORT 1234 // 設定伺服器端的埠
#define ARRAY_LENGTH 256 // 設定緩衝區的大小
/*
* 輸入一個字串,傳送給伺服器端
*/
int main(int argc, char **argv)
{
int iSocketClientFd; // 描述客服端socket的檔案描述符
struct sockaddr_in tSocketServerAddr;
int iSockAddrLen;
int iSendLen;
unsigned char ucSendBuf[ARRAY_LENGTH]; // 定義一個緩衝區
int iRet;
if(argc != 2)
{
printf("Usage :\n");
printf("%s <server_ip>\n", argv[0]);
return -1;
}
/* 1、開啟一個socket用於客服端 */
iSocketClientFd = socket(AF_INET, SOCK_DGRAM, 0);
if(iSocketClientFd == -1)
{
printf("socket error!\n");
return -1;
}
/* 2、connect */
/* 2.1 設定連結的伺服器端的基本資訊 */
tSocketServerAddr.sin_family = AF_INET; // 網路型別為ipv4
tSocketServerAddr.sin_port = htons(SOCKET_PORT); // 伺服器端的網路埠
iRet = inet_aton(argv[1], &tSocketServerAddr.sin_addr); // 客服端的ip地址
if(iRet == 0)
{
printf("server ip is not valid!\n");
return -1;
}
memset(tSocketServerAddr.sin_zero, 0, 8);
iSockAddrLen = sizeof(struct sockaddr);
/* 2.2 將伺服器端和客服端連結起來 */
iRet = connect(iSocketClientFd, (const struct sockaddr *)&tSocketServerAddr, iSockAddrLen);
if(iRet == -1)
{
printf("connect error!\n");
return -1;
}
printf("Input a message to %s: \n", argv[1]);
while(1)
{
if(fgets(ucSendBuf, ARRAY_LENGTH, stdin)) // 接收使用者的輸入
{
/* 3、將使用者的輸入傳送給伺服器端 */
iSendLen = send(iSocketClientFd, ucSendBuf, strlen(ucSendBuf), 0);
if(iSendLen <= 0)
{
printf("send error!\n");
close(iSocketClientFd);
return -1;
}
}
}
close(iSocketClientFd);
return 0;
}
2.2 直接進行通訊
a、開啟socket
/* 1、開啟客服端的socket */
iSocketClientFd = socket(AF_INET, SOCK_DGRAM, 0); // 網路型別為ipv4, 傳輸型別為udp
b、傳送資料
/* 2、強使用者端的輸入傳送給伺服器端 */
iSendLen = sendto(iSocketClientFd, ucSendBuf, strlen(ucSendBuf), 0,
(const struct sockaddr *)&tSocketServerAddr, iSockAddrLen);
完整的程式碼實現如下:#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SOCKET_PORT 1234 // 設定伺服器端的網路埠
#define ARRAY_LENGTH 256 // 設定緩衝區的大小
/*
* 從使用者端輸入一個字串,並把這個字串傳送給客服端
*/
int main(int argc, char **argv)
{
int iSocketClientFd; // 定義一個表示客服端socket的檔案描述符
struct sockaddr_in tSocketServerAddr;
int iSockAddrLen;
int iSendLen;
unsigned char ucSendBuf[ARRAY_LENGTH]; // 定義緩衝區
int iRet;
if(argc != 2)
{
printf("Usage :\n");
printf("%s <server_ip>\n", argv[0]);
return -1;
}
/* 1、開啟客服端的socket */
iSocketClientFd = socket(AF_INET, SOCK_DGRAM, 0); // 網路型別為ipv4, 傳輸型別為udp
if(iSocketClientFd == -1)
{
printf("socket error!\n");
return -1;
}
/* 設定要連結的伺服器端的基本資訊 */
tSocketServerAddr.sin_family = AF_INET; // 網路型別為ipv4
tSocketServerAddr.sin_port = htons(SOCKET_PORT); // 伺服器端的網路埠
iRet = inet_aton(argv[1], &tSocketServerAddr.sin_addr); // 要連線的客服端的ip地址
if(iRet == 0)
{
printf("server ip is not valid!\n");
return -1;
}
memset(tSocketServerAddr.sin_zero, 0, 8);
iSockAddrLen = sizeof(struct sockaddr);
printf("Input a message to %s: \n", argv[1]);
while(1)
{
if(fgets(ucSendBuf, ARRAY_LENGTH, stdin)) // 接收使用者端的輸入
{
/* 2、強使用者端的輸入傳送給伺服器端 */
iSendLen = sendto(iSocketClientFd, ucSendBuf, strlen(ucSendBuf), 0,
(const struct sockaddr *)&tSocketServerAddr, iSockAddrLen);
if(iSendLen <= 0)
{
printf("sendto error!\n");
close(iSocketClientFd);
return -1;
}
}
}
close(iSocketClientFd);
return 0;
}
三、測試
將上面兩種方式實現的客服端都和伺服器進行通訊測試。伺服器端和客服端可以在同一臺電腦上也可以在不同的電腦上(必須在同一區域網當中),本文是在同一臺電腦上對客服端和伺服器端進行測試,測試結果如下:
客服端一:
客服端二:
伺服器端:
從上面結果可以看出,伺服器和兩個客服端都通訊成功。