首页 > 系统相关 >Linux C網絡編程學習#1

Linux C網絡編程學習#1

时间:2024-08-18 18:16:38浏览次数:9  
标签:int ip argv char 編程 sockfd 網絡 學習 include

Linux C網絡編程學習#1

網絡編程的原理

兩台計算機的通信本質上是通過物理線路相連接,但通信的問題在於怎麼解讀這些電信號?這就從一個硬件的問題轉向了軟件的問題了。因此需要規定兩台計算機如何解讀相互傳輸的電信號,這種規定如何解讀另一台計算機的電信號(或報文)的程序就叫協議。

現代網絡普遍基於TCP/IP協議族和OSI協議族來實現計算機與計算機間的交流,由於博客園中已有很多相關介紹,本文在這不過多介紹。

Linux 網絡編程的接口

1. htonl函數和htons函數


uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostlong)

意義: 由於存儲兩個字節組成的整數有兩種方式(大端和小端),因此不同操作系統對一整數的存儲和解讀是不同的,由此我們需要確保所輸入的整數與對方所讀取的整數是一致的。

功能: htonl函數可用於將主機字節順序中的IPv4 地址轉換為網絡字節順序中的IPv4地址。

實驗代碼:


#include <stdio.h>
#include <arpa/inet.h>

int main(int argc, char *argv[]) {

	int a = 0x12345678;
	short b = 0x1234;
	
	printf("%#x\n", htonl(a));
	printf("%#x\n", htons(b));

	return 0;
}

2. inet_ntop函數

int inet_ntop(int af, const char * src, void * dst);

功能:用於將用整數表示的IPV4數據轉換成用字符串表示的IPV4數據。

實驗代碼:


#include <stdio.h>
#include <arpa/inet.h>

int main(int argc, char *argv[]) {

	// unsigned char的大小為1個字節,而int的大小為4個字節
	// 因此可以用4個unsigned char的變量去表達一個int的值。
	// 這樣做的好處是,由於IPV4是由4個字節組成的,因而可以用unsigned char分別輸入4個字節,然後存儲成一個整數。
	unsigned char ip_int[] = {192, 168, 3, 103};
	char ip_str[16] = ""; // "192.168.3.103"

	// 將一個表示IPV4的整數轉換成一個表示IPV4的字符串。
	inet_ntop(AF_INET, &ip_int, ip_str, 16);

	printf("ip_s = %s\n", ip_str);

	return 0;
}

3. inet_pton函數

const char * inet_ntop(int af, const void * src, char * dst, socklen_t size);

功能: 與inet_ntop功能相反。


#include <stdio.h>
#include <arpa/inet.h>

int main(int argc, char *argv[]) {

	char ip_str[] = "192.168.3.103";
	unsigned int ip_int = 0;
	unsigned char * ip_p = NULL;

	// 將點分十進制的IP地址轉化為無符號整數數據。
	inet_pton(AF_INET, ip_str, &ip_int);

	printf("ip_int = %d\n", ip_int);

	ip_p = (unsigned char *) &ip_int;
	printf("in_unit = %d.%d.%d.%d\n", *ip_p, *(ip_p + 1), *(ip_p + 2), *(ip_p + 3));

	return 0;
}

4. socket 函數

int socket(int domain, int type, int protocol);

功能: 創建套接字


#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {


	// 使用Socket函數創建套接字。
	// 用於UDP網絡編程的套接字。

	//  socket函數是一個創建套接字的函數接口,其返回值是一個整數,用於表示文件描述符。
	int sockfd;
	if ((sockfd=socket(AF_INET, SOCK_DGRAM, 0)) == -1)  {
		perror("failed  to create a socket");
		exit(1);
	}

	// sockfd 的值是3,因為socket是一種文件描述符,而在運行C時,編釋器會創建3個文件描述符,分別為標準輸入,標準輸出,標準錯誤輸出。
	printf("sockfd=%d\n", sockfd);

	return 0;
}

4. bind 函數

功能: 綁定IP和端口。


#include <netinet/in.h>
#include <string.h>

int main(int argc, char *argv[]) {

	// 0. 寫成通用命令行程序
	if (argc < 3) {
		fprintf(stderr, "Usage %s ip port", argv[0]);
		exit(0);
	}


	// 1. 創建套接字。
	int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	
	// 1.1 測試socket配置是否成功。
	if (sockfd == -1) {
		perror("[-] failed to create socket! [-]");
		exit(1);
	}

	// 2. 將網絡信息寫入結構體中
	struct sockaddr_in serveraddr;
	serveraddr.sin_family = AF_INET; // IPV4
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
	serveraddr.sin_port = htons(atoi(argv[2]));
	
	// 3. 將網絡信息與套接字綁定
	int err = bind(sockfd, (const struct sockaddr *) &serveraddr, sizeof(serveraddr));

	if (err == -1) {
		perror("failed to bind ip");
		exit(1);
	}

	return 0;
}

  1. recvform函數
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

功能: 接受UDP客戶端發的信息


#include <stdio.h>
#include <arpa/inet.h>		// inet_addr htons
#include <sys/socket.h>		// socket
#include <sys/types.h>		// AF_INET
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#define MESSAGE_BUF_MAX 200

int main(int argc, char *argv[]) {

	// 0. 寫成通用的命令行程序
	if (argc < 3)  {
		fprintf(stderr, "Usage %s ip port", argv[0]);
	}

	// 1. 創建套接字。
	int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	// 1.1 測試套接字的配置是否成功。
	if (sockfd == -1) {
		perror("failed to create socket");
		exit(1);
	}

	// 2. 將網絡信息寫人結構體
	struct sockaddr_in serveraddr;
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
	serveraddr.sin_port = htons(atoi(argv[2]));

	// 3. 綁定IP
	int err = bind(sockfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr));
	// 3.1 測試IP是否綁定成功
	if (err == -1)  {
		perror("failed to bind ip");
		exit(1);
	}

	char buf[MESSAGE_BUF_MAX];
	struct sockaddr_in clientaddr;
	socklen_t addrlen = sizeof(struct sockaddr_in);

	// 4. 接受信息
	while (true) {
		
		err = recvfrom(sockfd, buf, MESSAGE_BUF_MAX, 0, (const struct sockaddr *)  &clientaddr, &addrlen);

		if (err == -1) {
			perror("failed to receive the client message");
			exit(1);
		}

		// 打印Client的網絡信息
		printf("ip:%s, port:%d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));

		// 打印Client發出的Message
		puts(buf);
		putchar('\n');

	}

	

	return 0;
}

  1. sendto 函數
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

cat main.c
#include <stdio.h>		 // printf fgets
#include <stdlib.h>		 // exit
#include <unistd.h>		 // close
#include <string.h>      // strlen
#include <stdbool.h>
#include <arpa/inet.h>	 // inet_addr htons
#include <sys/types.h>	 // AF_INET
#include <sys/socket.h>	 // socket
#include <netinet/in.h>  // sockaddr_in

#define MESSAGE_BUF_MAX 200

int main(int argc, char *argv[]) {

	// 寫一個通用的終端程序
	if (argc < 3) {
		fprintf(stderr, "Usage: %s ip port\n", argv[0]);
		exit(1);
	}

	// 1. 創建套接字IPV4, UDP
	int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	
	// 1.1 測試套接字是否配置成功
	if (sockfd == -1) {
		perror("[-]\tfailed to create socket![-]");
		exit(0);
	}

	// 2. 配置目標主機的IP和PORT。
	struct sockaddr_in destination_address;
	socklen_t addrlen = sizeof(destination_address);
	
	destination_address.sin_family = AF_INET; // IPV4
	destination_address.sin_addr.s_addr = inet_addr(argv[1]); // ip 地址,由於要將IP轉成無符號整數類型用於儲存,因此使用inet_addr函數轉換。
	destination_address.sin_port = htons(atoi(argv[2])); // sin_port 的類型本質是unsigned short int,其sizeof為2Byte,而又因為不知道其他主機的操作系統是小端模式,還是大端模式,因而使用htons做轉換。

	// 3. 使用sendto函數向UDP伺服器發送數據。
	// 由於UDP是無連接的,因此無需在發送數據前先建立連接。

	char buf[MESSAGE_BUF_MAX];

	while (true){
		fgets(buf, MESSAGE_BUF_MAX, stdin);
		buf[strlen(buf)-1] =  '\0';
		if (sendto(sockfd, buf, MESSAGE_BUF_MAX, 0, (struct sockaddr *) &destination_address, addrlen) == -1) {
			perror("[-]\tconnect error\t[-]\n");
			exit(1);
		}
	}

	// 關閉套接字文件。
	close(sockfd);

	return 0;
}

參考

https://www.die.net/

标签:int,ip,argv,char,編程,sockfd,網絡,學習,include
From: https://www.cnblogs.com/yugawakun/p/18365892

相关文章

  • 深度學習筆記05-使用CNN進行猴痘識別(Tensorflow)
    前言一、我的環境二、準備套件三、GPU設置四、導入數據五、數據預處理六、可視化數據七、配置數據集八、建構CNN網路九、編譯模型十、訓練模型十一、模型評估十二、使用最佳模型權重進行預測十三、總結前言......
  • 深度學習筆記04-使用CNN進行天氣圖片識別(Tensorflow)
    前言一、我的環境二、準備套件三、GPU設置四、導入數據五、查看數據六、數據預處理七、可視化數據八、配置數據集九、建構CNN網路十、編譯模型十一、訓練模型十二、模型評估十三、預測十四、總結前言......
  • 探索網絡時代的注意力管理:如何平衡專注與捕捉
    在這個資訊爆炸的時代,如何有效地管理我們的注意力,並在專注與捕捉之間找到平衡,已經成為我們面臨的一個重要問題。專注模式與捕捉模式是我們在生活與工作中交替運用的兩種不同的注意力模式,而如何在兩者之間取得平衡,則是高效注意力管理的關鍵。然而,網絡時代為我們帶來的資訊超載和注......
  • NVIDIA Maxine Video Effects SDK 編程指南 - 实践小记
    NVIDIAMaxineVideoEffectsSDK編程指南 -实践小记本篇博客重点只说VideoEffect的部分,此外还有AudioEffect的部分、还有AR部分,不在本篇范围内。本文由重庆Debug原创NVIDIAMaxineVideoEffects支持基于AI的视觉效果,这些效果可以输入标准网络摄像头画面数据,同时也可以......
  • C Primer Plus (7.12) 編程練習
    /*CPrimerPlus(7.11)3*/1#include<stdio.h>2intmain()3{4doubleweight,height;5printf("Pleaseenteryourweightandheight.\n");6......
  • GYM 101522 La Salle-Pui Ching Programming Challenge 培正喇沙編程挑戰賽 2017
    C.Cheering题意:判断一个字符串中\(LSC\),\(PCMS\)哪个字符穿出现的次数多,如果一样多输出\(Tie\)思路:模拟就行signedmain(){std::strings;......
  • La Salle-Pui Ching Programming Challenge 培正喇沙編程挑戰賽 2017
    练习题目来源A-AmbiguousDatas题意定义一年\(M\)个月,每个月\(Di\)天,现在日期有两种表达方式dd/mm/year和mm/dd/year,这样会产生歧义,例如,1/2/12就是歧义的,而1/1......
  • C Primer Plus (6.16) 編程練習
    /*CPrimerPlus(6.15)6*/1#include<stdio.h>2intmain()3{4inti,j;5for(inti=0;i<4;i++)6{7for(intj=0;j<8;j++)8{9printf("$");1......
  • C Primer Plus 5.11 編程練習
    /*CPrimerPlus(5.10)9*/1#include<stdio.h>2#defineG1033intmain()4{5charch=96;67while(ch++<G)8{9printf......
  • C Primer Plus(4.8)編程練習
    /*CPrimerPlus(4.7)5*/1include<stdio.h>2#defineBOOK"WarandPeace"3intmain(void)4{5floatcost=12.99;6floatpercent=80.0;7......