日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

C语言网络编程

發布時間:2023/12/29 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C语言网络编程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 套接字
      • Linux下的套接字
      • Windows下的套接字
      • 建立Socket
      • bind() 函數
      • connect() 函數
      • linsten() 函數
      • accept() 函數
      • Linux 接受和發送數據
      • Windos 接受和發送數據
    • 示例
      • Windows
      • Linux
    • 參考

套接字

socket,套接字,它是計算機之間進行通信的一種約定或一種方式。通過 socket 這種約定,一臺計算機可以接收其他計算機的數據,也可以向其他計算機發送數據。


Linux下的套接字

Linux中創建的文件都有一個 int 類型的編號,稱為文件描述符(File Descriptor)。使用文件時,只要知道文件描述符就可以。socket 也被認為是文件的一種,和普通文件的操作沒有區別

Windows下的套接字

WinSock(Windows Socket)編程依賴于系統提供的動態鏈接庫(DLL),有兩個版本:

  • 較早的DLL是 wsock32.dll,大小為 28KB,對應的頭文件為 winsock1.h;
  • 最新的DLL是 ws2_32.dll,大小為 69KB,對應的頭文件為 winsock2.h。

加載ws2_32.dll

#pragma comment (lib, "ws2_32.lib")

WSAStartup()

使用DLL之前,還需要調用 WSAStartup() 函數進行初始化,以指明 WinSock 規范的版本

int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
  • wVersionRequested 為 WinSock 規范的版本號,低字節為主版本號,高字節為副版本號(修正版本號)
  • lpWSAData 為指向 WSAData 結構體的指針。

eg:

WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData);

建立Socket


Linux

int socket(int af, int type, int protocol);
  • af ,地址族(Address Family),常用AF_INET(IPv4) 和 AF_INET6(IPv6)。
  • type ,數據傳輸方式,常用的有 SOCK_STREAM(面向連接)和 SOCK_DGRAM(無連接)
  • protocol 表示傳輸協議,常用的有 IPPROTO_TCP(TCP協議) 和 IPPTOTO_UDP(UDP協議)

1.TCP socket

int tcp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

2.UDP socket

int udp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

Windows

SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); //創建TCP套接字

bind() 函數

將套接字與特定的IP地址和端口綁定起來

int bind(int sock, struct sockaddr *addr, socklen_t addrlen); //Linux int bind(SOCKET sock, const struct sockaddr *addr, int addrlen); //Windows

示例

//創建套接字 int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //創建sockaddr_in結構體變量 struct sockaddr_in serv_addr;memset(&serv_addr, 0, sizeof(serv_addr)); //每個字節都用0填充serv_addr.sin_family = AF_INET; //使用IPv4地址 serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具體的IP地址 serv_addr.sin_port = htons(1234); //端口//將套接字和IP、端口綁定 bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

1、sockaddr_in 結構體

struct sockaddr_in{sa_family_t sin_family; //地址族(Address Family),也就是地址類型uint16_t sin_port; //16位的端口號struct in_addr sin_addr; //32位IP地址char sin_zero[8]; //不使用,一般用0填充 };
  • sin_family 和 socket() 的第一個參數的含義相同,取值也要保持一致。

  • sin_prot 為端口號。需要用 htons() 函數轉換

  • sin_addr 是 struct in_addr 結構體類型的變量

    in_addr 結構體

    struct in_addr{ in_addr_t s_addr; //32位的IP地址 };

    需要inet_addr()轉換

    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

2、sockaddr

bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

bind() 第二個參數的類型為 sockaddr,而代碼中卻使用 sockaddr_in,然后再強制轉換為 sockaddr,這是為什么呢?

sockaddr 結構體的定義如下:

struct sockaddr{sa_family_t sin_family; //地址族(Address Family),也就是地址類型char sa_data[14]; //IP地址和端口號 };

下圖是 sockaddr 與 sockaddr_in 的對比(括號中的數字表示所占用的字節數):

sockaddr 和 sockaddr_in 的長度相同,都是16字節,只是將IP地址和端口號合并到一起,用一個成員 sa_data 表示。要想給 sa_data 賦值,必須同時指明IP地址和端口號,例如”127.0.0.1:80“,遺憾的是,沒有相關函數將這個字符串轉換成需要的形式,也就很難給 sockaddr 類型的變量賦值,所以使用 sockaddr_in 來代替。這兩個結構體的長度相同,強制轉換類型時不會丟失字節,也沒有多余的字節。


connect() 函數

建立連接

與bind類似

int connect(int sock, struct sockaddr *serv_addr, socklen_t addrlen); //Linux int connect(SOCKET sock, const struct sockaddr *serv_addr, int addrlen); //Windows

linsten() 函數

套接字進入被動監聽狀態

int listen(int sock, int backlog); //Linux int listen(SOCKET sock, int backlog); //Windows
  • sock 需要進入監聽狀態的套接字
  • backlog 請求隊列的最大長度


accept() 函數

套接字處于監聽狀態時,接收客戶端請求,返回新的套接字

int accept(int sock, struct sockaddr *addr, socklen_t *addrlen); //Linux SOCKET accept(SOCKET sock, struct sockaddr *addr, int *addrlen); //Windows
  • sock 為服務器端套接字
  • addr 為 sockaddr_in 結構體變量
  • addrlen 為參數 addr 的長度,可由 sizeof() 求得


Linux 接受和發送數據

write()

寫入數據

ssize_t write(int fd, const void *buf, size_t nbytes);
  • fd 為要寫入的文件的描述符
  • buf 為要寫入的數據的緩沖區地址
  • nbytes 為要寫入的數據的字節數。

read()

讀取數據

ssize_t read(int fd, void *buf, size_t nbytes);
  • fd 為要讀取的文件的描述符
  • buf 為要接收數據的緩沖區地址
  • nbytes 為要讀取的數據的字節數。


Windos 接受和發送數據

send()

發送數據

int send(SOCKET sock, const char *buf, int len, int flags);
  • sock 為要發送數據的套接字
  • buf 為要發送的數據的緩沖區地址
  • len 為要發送的數據的字節數
  • flags 為發送數據時的選項,一般設置為 0 或 NULL

recv()

接受數據

int recv(SOCKET sock, char *buf, int len, int flags);

同上


示例

Windows

server

#include <stdio.h> #include <winsock2.h> #pragma comment (lib, "ws2_32.lib") //加載 ws2_32.dll int main(){//初始化 DLLWSADATA wsaData;WSAStartup(MAKEWORD(2, 2), &wsaData);//創建套接字 PF_INET:IPv4SOCKET servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);//綁定套接字sockaddr_in sockAddr;memset(&sockAddr, 0, sizeof(sockAddr)); //每個字節都用0填充sockAddr.sin_family = PF_INET; //使用IPv4地址sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具體的IP地址sockAddr.sin_port = htons(1234); //端口bind(servSock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));//進入監聽狀態listen(servSock, 20);//接收客戶端請求SOCKADDR clntAddr;int nSize = sizeof(SOCKADDR);SOCKET clntSock = accept(servSock, (SOCKADDR*)&clntAddr, &nSize);//向客戶端發送數據char *str = "Hello World!";send(clntSock, str, strlen(str)+sizeof(char), NULL);//關閉套接字closesocket(clntSock);closesocket(servSock);//終止 DLL 的使用WSACleanup();return 0; }

client

#include <stdio.h> #include <stdlib.h> #include <WinSock2.h> #pragma comment(lib, "ws2_32.lib") //加載 ws2_32.dll int main(){//初始化DLLWSADATA wsaData;WSAStartup(MAKEWORD(2, 2), &wsaData);//創建套接字SOCKET sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);//向服務器發起請求sockaddr_in sockAddr;memset(&sockAddr, 0, sizeof(sockAddr)); //每個字節都用0填充sockAddr.sin_family = PF_INET;sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");sockAddr.sin_port = htons(1234);connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));//接收服務器傳回的數據char szBuffer[MAXBYTE] = {0};recv(sock, szBuffer, MAXBYTE, NULL);//輸出接收到的數據printf("Message form server: %s\n", szBuffer);//關閉套接字closesocket(sock);//終止使用 DLLWSACleanup();system("pause");return 0;

Linux

服務器端代碼 server.cpp

#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #include <netinet/in.h> int main(){//創建套接字int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//將套接字和IP、端口綁定struct sockaddr_in serv_addr;memset(&serv_addr, 0, sizeof(serv_addr)); //每個字節都用0填充serv_addr.sin_family = AF_INET; //使用IPv4地址serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具體的IP地址serv_addr.sin_port = htons(1234); //端口bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));//進入監聽狀態,等待用戶發起請求listen(serv_sock, 20);//接收客戶端請求struct sockaddr_in clnt_addr;socklen_t clnt_addr_size = sizeof(clnt_addr);int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);//向客戶端發送數據char str[] = "Hello World!";write(clnt_sock, str, sizeof(str));//關閉套接字close(clnt_sock);close(serv_sock);return 0; }

客戶端代碼 client.cpp:

#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> int main(){//創建套接字int sock = socket(AF_INET, SOCK_STREAM, 0);//向服務器(特定的IP和端口)發起請求struct sockaddr_in serv_addr;memset(&serv_addr, 0, sizeof(serv_addr)); //每個字節都用0填充serv_addr.sin_family = AF_INET; //使用IPv4地址serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具體的IP地址serv_addr.sin_port = htons(1234); //端口connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));//讀取服務器傳回的數據char buffer[40];read(sock, buffer, sizeof(buffer)-1);printf("Message form server: %s\n", buffer);//關閉套接字close(sock);return 0; }

參考

C語言網絡編程_C語言中文網

總結

以上是生活随笔為你收集整理的C语言网络编程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。