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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

LinuxC网络编程

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

文章目錄

  • 一、socket
  • 二、bind
  • 三、setsockopt
  • 四、listen(TCP服務端)
  • 五、accept(TCP服務端)
  • 六、connect(TCP客戶端)
  • 七、send&recv(TCP)
  • 八、sendto&recvfrom(UDP)
  • 九、shutdown
  • 十、epoll_create
  • 十一、epoll_ctl
  • 十二、epoll_wait
  • 十三、循環服務器模型(TCP)
  • 十四、循環服務器模型(UDP)
  • 十五、并發服務器模型(TCP多線程)
  • 十六、并發服務器模型(TCP多進程)

一、socket

#include <sys/types.h> #include <sys/socket.h>int socket(int domain, int type, int protocol);

功能:創建一個套接字文件,然后以文件形式來操作通信,不過套接字文件沒有文件名。

參數

  • domain:用于指定協議族是IPV4還是IPV6,分別對應參數AF_INET和參數AF_INET6。
  • type:套接字類型,用于進一步指定使用協議族中的哪個子協議來通信:
    ①如果指定為SOCK_STREAM,表示使用TCP協議;
    ②如果指定為SOCK_DGRAM,表示使用UDP協議;
    ③如果指定為SOCK_RDM,表示使用原始網絡通信,即IP協議;
    ④如果指定為SOCK_NONBLOCK,表示將socket返回的文件描述符指定為非阻塞的,它可以與前面的宏進行或運算。
  • protocol:表示傳輸協議,一般情況下可以直接寫0,有操作系統自動推演出應該使用什么協議。

返回值:成功返回套接字描述符,失敗返回-1并設置errno。


二、bind

#include <sys/types.h> #include <sys/socket.h>#include <netinet/in.h>int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);struct sockaddr_in {short int sin_family; /* Internet地址族 */unsigned short int sin_port; /* 端口號 */struct in_addr sin_addr; /* IP地址 */unsigned char sin_zero[8]; /* 填0 */ };struct in_addr {unsigned long s_addr; /* IPV4的32位IP地址 */ };

功能:將指定了通信協議的套接字文件與IP以及端口綁定起來。

參數

  • sockfd:套接字的文件描述符。
  • addr:指定要綁定的參數信息。編程中一般并不直接針對sockaddr數據結構操作,而是使用與sockaddr等價的sockaddr_in數據結構。
  • addrlen:第二個參數的結構的長度。

此外,由于網絡字節序有一般采用大端(高尾端)排序方式,所以從主機向網絡發送和從網絡向主機接收時要進行字節序的轉換

#include <arpa/inet.h>uint32_t htonl(uint32_t hostlong); /* host to network short */ uint16_t htons(uint16_t hostshort); /* host to network short */ uint32_t ntohl(uint32_t netlong); /* network to host long */ uint16_t ntohs(uint16_t netshort); /* network to host short */

同時,IP地址的格式也要在字符串和32位整數之間相互轉化

#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>int inet_aton(const char *cp, struct in_addr *inp); in_addr_t inet_addr(const char *cp); in_addr_t inet_network(const char *cp); char *inet_ntoa(struct in_addr in); struct in_addr inet_makeaddr(in_addr_t net, in_addr_t host); in_addr_t inet_lnaof(struct in_addr in); in_addr_t inet_netof(struct in_addr in);

三、setsockopt

#include <sys/types.h> #include <sys/socket.h>int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

如果是服務器主動關閉連接,默認需要等待2MSL才能將端口資源釋放,這會導致此端口短時間內無法重用,于是我們通過下面這段函數將該socket設置為可重用:

/* 設置套接字為可重用 */ int option = 1; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));


四、listen(TCP服務端)

#include <sys/types.h> #include <sys/socket.h>int listen(int sockfd, int backlog);

功能:將套接字文件描述符,從主動文件描述符變為被動文件描述符,然后用于被動監聽客戶的連接。

參數

  • sockfd:socket返回的套接字文件描述符。
  • backlog:指定的隊列容量,這個隊列用于記錄正在連接,但是還沒連接完成的客戶,一般將隊列容量指定為2、3即可。這個容量并沒有什么統一的設定值,一般來說只要小于30即可。

五、accept(TCP服務端)

#include <sys/types.h> #include <sys/socket.h>int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);#define _GNU_SOURCE #include <sys/socket.h>int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);

功能:被動監聽客戶發起三次握手的連接請求,三次握手成功,即建立連接成功。accept被動監聽客戶連接的過程其實也是監聽客戶上線的過程。對于那些只連接了一般,還未連接完成的客戶,會被記錄到未完成隊列中,隊列的容量由listen函數的第二個參數backlog來指定。服務端調用accept函數監聽連接,客戶端調用connect來請求連接。一旦連接成功,服務器這邊的TCP協議會記錄客戶的IP和端口,如果是跨網通信的,記錄IP的就是客戶所在的路由器的公網IP。

參數

  • sockfd:一個已經通過listen函數轉化的被動套接字文件描述符。
  • addr:用于記錄發起連接請求的那個客戶端的IP和端口。
  • addrlen:用一個變量記錄第二個參數的長度,addrlen對應這個變量的地址。

返回值:如果執行成功返回新的套接字文件描述符,否則返回-1并設置errno。


六、connect(TCP客戶端)

#include <sys/types.h> #include <sys/socket.h>int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

功能:向服務器主動發起連接請求,即主動發起三次握手。

參數

  • sockfd:socket函數所返回的套接字文件描述符。
  • addr:用于設置你所要連接的服務器的IP和端口。如果只是純粹的局域網內部通信的話,IP就是局域網IP,但如果是跨網通信的話,IP必須是服務器所在的路由器的公網IP。為了方便操作,在應用層我們還是使用struct sockaddr_in來設置,然后傳遞給connect時在強制轉換為struct sockaddr。
  • addrlen:第二個參數所指定的結構體變量的大小。

七、send&recv(TCP)

#include <sys/types.h> #include <sys/socket.h>ssize_t send(int sockfd, const void *buf, size_t len, int flags); ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);ssize_t recv(int sockfd, void *buf, size_t len, int flags); ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

功能:向對方發送數據或從對方接收數據。

參數

  • sockfd:用于通信的通信描述符。通信描述符在客戶端對應socket函數生成的套接字描述符,在服務端則是accept返回的套接字描述符。
  • buf:應用緩存,存放要發送的或待接收的數據,一般情況下為一個結構體。
  • flags:一般置為0,表示阻塞發送或阻塞接收,如果想要非阻塞讀取或發送則置為MSG_DONTWAIT。

八、sendto&recvfrom(UDP)

#include <sys/types.h> #include <sys/socket.h>ssize_t send(int sockfd, const void *buf, size_t len, int flags); ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);ssize_t recv(int sockfd, void *buf, size_t len, int flags); ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

功能:發送或接收數據,最后兩個參數均為NULL時功能與send和recv相同。

參數

  • sockfd:socket返回的套接字。對于UDP來說,套接字描述符直接用于通信。
  • buf:存放數據的應用緩存。
  • len:應用緩存的大小。
  • flags:一般寫0,表示阻塞發送數據。
  • dest_addr&src_addr:IP地址以及端口等套接字信息。由于UDP不面向連接,無法自動記錄對方的套接字信息,所以每次數據的發送都需要指定套接字信息。
  • addrlen:套接字信息結構體的大小。

返回值:成功返回發送或接收到的字節數,失敗返回-1并設置errno。


九、shutdown

#include <sys/socket.h>int shutdown(int sockfd, int how);

功能:可以按照要求關閉連接,而且不管有多少個描述符指向同一個連接,shutdown可以一次性將其全部關閉。

參數

  • sockfd:服務端使用accept函數返回的描述符。
  • how:如何斷開連接。SHUT_RD只斷開讀連接,SHUT_WR只斷開寫連接,SHUT_RDWR將讀、寫連接全部斷開。

shutdown與close的區別:

  • close只能將讀寫同時關閉,而shutdown可以選擇性關閉。
  • close只能關閉單個描述符,二shutdown在關閉時會將如選定連接有關的全部描述符關閉。

  • 十、epoll_create

    #include <sys/epoll.h>int epoll_create(int size); int epoll_create1(int flags);

    功能:epoll_create()函數用于創建一個epoll實例,它實際上是由一個紅黑樹來實現的。

    參數

    • size:用于告訴內核這個epoll需要關注的描述符的大致數目而不是最大個數。實際上Linux在2.6.8版本以后會忽略這個參數,但這個參數必須大于零。當容量不足時epoll會自動擴容。

    返回值:返回創建的epoll紅黑樹的文件描述符。


    十一、epoll_ctl

    #include <sys/epoll.h>int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);typedef union epoll_data {void *ptr;int fd;uint32_t u32;uint64_t u64; } epoll_data_t;struct epoll_event {uint32_t events; /* Epoll events */epoll_data_t data; /* User data variable */ };

    功能:用于操作創建的epoll實例,主要包括增加、修改和刪除三種操作。

    參數

    • epfd:epoll的文件描述符。
    • op:對epoll執行的操作,主要包括:
      ①EPOLL_CTL_ADD,向epoll中注冊新的文件描述符。
      ②EPOLL_CTL_MOD,修改已注冊文件描述符的監聽事件。
      ③EPOLL_CTL_DEL,從epoll中刪除文件描述符。
    • fd:操作關聯的文件描述符。
    • event:告訴內核要監聽什么事件,實際上epoll的紅黑樹每個結點上都對應一個epoll_event類型的結構體。結構體中的成員events主要包括以下宏:
      ①EPOLLIN:表示對應的文件描述符可以讀。
      ②EPOLLOUT:表示對應的文件描述符可以寫。
      ③EPOLLPRI:表示對應的文件描述符有緊急數據或者帶外數據到來。
      ④EPOLLERR:表示對應的文件描述符發生錯誤。
      ⑤EPOLLHUP:表示對應的文件描述符被掛斷。
      ⑥EPOLLET:將epoll設置為邊緣觸發模式。
      ⑦EPOLLONESHOT:只監聽一次事件,當監聽完這次事件后,如果還需要繼續監聽這個socket的話,需要將它再次加入到epoll隊列里。

    返回值:執行成功返回0,否則返回-1并設置errno的值。


    十二、epoll_wait

    #include <sys/epoll.h>int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout); int epoll_pwait(int epfd, struct epoll_event *events, int maxevents, int timeout, const sigset_t *sigmask);

    功能

    參數

    • epfd:epoll的文件描述符。
    • events:一個結構體指針,當監聽的文件描述符發生改變時,內核會把發生了改變的epoll_event拷貝到這個參數里。
    • maxevents:數組的容量。
    • timeout:超時信息:
      ①為-1時表示永久阻塞。
      ②為0時表示立即返回。
      ③取>0時表示監聽到目標數目的文件描述符時再返回。

    返回值:執行成功返回發出請求的文件描述符的個數,執行失敗返回-1并設置error。


    十三、循環服務器模型(TCP)

    服務端 server.c

    #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <errno.h>#include <stdio.h> #include <stdlib.h> #include <string.h>#define PORT 2015 #define IP "192.168.179.129" #define MAX_SIZE 1024int main() {int sockfd;//服務器套接字描述符int client_sockfd;//通信套接字描述符char buffer[MAX_SIZE];//數據緩沖區struct sockaddr_in server_addr;//服務器套接字信息struct sockaddr_in client_addr;//客戶端套接字信息/* 獲取服務器套接字文件描述符 */sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd == -1) {perror("socket error");exit(1);}/* 初始化服務器套接字信息 */memset(&server_addr, 0, sizeof(struct sockaddr_in));server_addr.sin_family = AF_INET;//使用IPv4server_addr.sin_port = htons(PORT);//對端口進行字節序轉化server_addr.sin_addr.s_addr = inet_addr(IP);//對IP地址進行格式轉化/* 因為最后需要服務器主動關閉連接,所以要設置服務器套接字為可重用 */int option = 1;setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));/* 綁定服務器套接字信息 */if (bind(sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr_in)) < 0) {perror("bind error");exit(1);}/* 將服務器套接字轉化為被動監聽 */if (listen(sockfd, 3) < 0) {perror("listen error!");exit(1);}/* 與客戶端進行串行連接 */while(1) {printf("[server] Server is waiting······\n");/* 等待客戶端的連接 */int len = sizeof(struct sockaddr_in);//通信套接字結構體長度memset(&client_addr, 0, sizeof(struct sockaddr_in));if ((client_sockfd = accept(sockfd, (struct sockaddr *)(&client_addr), &len)) < 0) {perror("accept error");exit(1);}printf("[server] Client's port is %d, ip is %s\n", ntohs(client_addr.sin_port), inet_ntoa(client_addr.sin_addr));/* 接收客戶端的消息 */memset(buffer, 0, MAX_SIZE);recv(client_sockfd, buffer, sizeof(buffer), 0);printf("[server] Client's message:%s\n", buffer);/* 向客戶端發送消息 */send(client_sockfd, "I have received your message.", 30, 0);/* 關閉連接 */shutdown(client_sockfd, SHUT_RDWR);}return 0; }

    客戶端 client.c

    #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <errno.h>#include <stdio.h> #include <stdlib.h> #include <string.h>#define PORT 2015 #define IP "192.168.179.129" #define MAX_SIZE 1024int main() {int sockfd;//客戶端套接字描述符char buffer[MAX_SIZE];//收發數據緩沖區struct sockaddr_in server_addr;//服務器套接字描述符/* 獲取客戶端套接字文件描述符 */if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {perror("socket error");exit(1);}/* 初始化服務器套接字信息 */memset(&server_addr, 0, sizeof(struct sockaddr_in));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(PORT);server_addr.sin_addr.s_addr = inet_addr(IP);/* 向服務器發送連接請求 */if (connect(sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr_in)) < 0) {perror("connect error");exit(1);}printf("[client] Connect successfully.\n");/* 向服務器發送消息 */printf("[client] Please input your message>>>");memset(buffer, 0, MAX_SIZE);scanf("%[^\n]%*c", buffer);send(sockfd, buffer, strlen(buffer), 0);/* 接收服務端的消息 */memset(buffer, 0, MAX_SIZE);recv(sockfd, buffer, sizeof(buffer), 0);printf("[client] Server's message:%s\n", buffer);return 0; }

    運行結果


    十四、循環服務器模型(UDP)

    服務端 server.c

    #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <errno.h>#include <stdio.h> #include <stdlib.h> #include <string.h>#define CLIENT_PORT 2015 #define SERVER_PORT 2025 #define IP "192.168.179.129" #define MAX_SIZE 1024int main() {int sockfd;//服務端套接字描述符char buffer[MAX_SIZE];//收發數據緩沖區struct sockaddr_in client_addr;//客戶端套接字信息struct sockaddr_in server_addr;//服務端套接字信息/* 獲取服務端套接字描述符 */if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {perror("socket error");exit(1);}/* 初始化服務端套接字信息 */memset(&server_addr, 0, sizeof(struct sockaddr_in));server_addr.sin_family = AF_INET;server_addr.sin_port = (SERVER_PORT);server_addr.sin_addr.s_addr = inet_addr(IP);/* 綁定接收端信息 */if (bind(sockfd, (struct sockaddr *) &server_addr, sizeof(struct sockaddr_in)) < 0) {perror("bind error");exit(1);}/* 接收消息 */while (1) {/* 初始化客戶端套接字信息 */memset(&client_addr, 0, sizeof(struct sockaddr_in));client_addr.sin_family = AF_INET;client_addr.sin_port = (CLIENT_PORT);client_addr.sin_addr.s_addr = inet_addr(IP);/* 收發消息 */printf("[server] Srever is waiting······\n");int len = sizeof(struct sockaddr_in);memset(buffer, 0, sizeof(buffer));recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *) &client_addr, &len);printf("[server] Client's port is %d, ip is %s.\n", ntohs(client_addr.sin_port), inet_ntoa(client_addr.sin_addr));printf("[server] Client's message:%s\n", buffer);memset(buffer, 0, sizeof(buffer));sendto(sockfd, "I have received your message.", 30, 0, (struct sockaddr *) &client_addr, sizeof(struct sockaddr_in));}return 0; }

    客戶端 client.c

    #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <errno.h>#include <stdio.h> #include <stdlib.h> #include <string.h>#define CLIENT_PORT 2015 #define SERVER_PORT 2025 #define IP "192.168.179.129" #define MAX_SIZE 1024int main() {int sockfd;//客戶端套接字描述符char buffer[MAX_SIZE];//收發數據緩沖區struct sockaddr_in client_addr;//客戶端套接字信息struct sockaddr_in server_addr;//服務端套接字信息/* 獲取客戶端套接字描述符 */if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {perror("socket error");exit(1);}/* 初始化服務端套接字信息 */memset(&client_addr, 0, sizeof(struct sockaddr_in));client_addr.sin_family = AF_INET;client_addr.sin_port = (CLIENT_PORT);client_addr.sin_addr.s_addr = inet_addr(IP);/* 綁定接收端信息 */if (bind(sockfd, (struct sockaddr *) &client_addr, sizeof(struct sockaddr_in)) < 0) {perror("bind error");exit(1);}/* 接收消息 */while (1) {/* 初始化服務端套接字信息 */memset(&server_addr, 0, sizeof(struct sockaddr_in));server_addr.sin_family = AF_INET;server_addr.sin_port = (SERVER_PORT);server_addr.sin_addr.s_addr = inet_addr(IP);/* 收發消息 */printf("[client] Please input your message>>>");memset(buffer, 0, sizeof(buffer));scanf("%[^\n]%*c", buffer);sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr *) &server_addr, sizeof(struct sockaddr_in));int len = sizeof(struct sockaddr_in);recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *) &server_addr, &len);printf("[client] Server's port is %d, ip is %s.\n", ntohs(server_addr.sin_port), inet_ntoa(server_addr.sin_addr));printf("[client] Server's message:%s\n", buffer);memset(buffer, 0, sizeof(buffer));}return 0; }

    運行結果


    十五、并發服務器模型(TCP多線程)

    服務端 server.c

    #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <pthread.h> #include <errno.h>#include <stdio.h> #include <stdlib.h> #include <string.h>#define PORT 2015 #define IP "192.168.179.129" #define MAX_SIZE 1024void *recv_thread_fun(void *arg);int main() {int server_sockfd;//服務器套接字描述符int client_sockfd;//通信套接字描述符pthread_t recv_thread_id;struct sockaddr_in server_addr;//服務器套接字信息struct sockaddr_in client_addr;//客戶端套接字信息/* 獲取服務器套接字文件描述符 */server_sockfd = socket(AF_INET, SOCK_STREAM, 0);if (server_sockfd == -1) {perror("socket error");exit(1);}/* 初始化服務器套接字信息 */memset(&server_addr, 0, sizeof(struct sockaddr_in));server_addr.sin_family = AF_INET;//使用IPv4server_addr.sin_port = htons(PORT);//對端口進行字節序轉化server_addr.sin_addr.s_addr = inet_addr(IP);//對IP地址進行格式轉化/* 因為最后需要服務器主動關閉連接,所以要設置服務器套接字為可重用 */int option = 1;setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));/* 綁定服務器套接字信息 */if (bind(server_sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr_in)) < 0) {perror("bind error");exit(1);}/* 將服務器套接字轉化為被動監聽 */if (listen(server_sockfd, 3) < 0) {perror("listen error!");exit(1);}/* 與客戶端進行串行連接 */while(1) {printf("[server] Server is waiting······\n");/* 等待客戶端的連接 */int len = sizeof(struct sockaddr_in);//通信套接字結構體長度memset(&client_addr, 0, sizeof(struct sockaddr_in));if ((client_sockfd = accept(server_sockfd, (struct sockaddr *)(&client_addr), &len)) < 0) {perror("accept error");exit(1);}printf("[server] Client %d port is %d, ip is %s.\n", client_sockfd,ntohs(client_addr.sin_port), inet_ntoa(client_addr.sin_addr));/* 創建子線程用于收發消息 */if (pthread_create(&recv_thread_id, NULL, recv_thread_fun, (void *) &client_sockfd) != 0) {perror("pthread create error");exit(1);}}return 0; }/* 子線程運行函數 */ void *recv_thread_fun(void *arg) {int client_sockfd = *((int *) arg);char buffer[MAX_SIZE];//數據緩沖區pthread_detach(pthread_self());//將本線程轉換為分離態,由系統自動回收資源while (1) {/* 接收客戶端的消息 */memset(buffer, 0, MAX_SIZE);if (recv(client_sockfd, buffer, sizeof(buffer), 0) == 0) {/* 監測客戶端的退出 */printf("[server] Client %d has exited.\n", client_sockfd);pthread_exit(NULL);}printf("[server] Client %d message:%s\n", client_sockfd, buffer);/* 向客戶端發送消息 */send(client_sockfd, "I have received your message.", 30, 0);} }

    客戶端 client.c

    #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <errno.h>#include <stdio.h> #include <stdlib.h> #include <string.h>#define PORT 2015 #define IP "192.168.179.129" #define MAX_SIZE 1024int main() {int client_sockfd;//客戶端套接字描述符char buffer[MAX_SIZE];//收發數據緩沖區struct sockaddr_in server_addr;//服務器套接字描述符/* 獲取客戶端套接字文件描述符 */if((client_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {perror("socket error");exit(1);}/* 初始化服務器套接字信息 */memset(&server_addr, 0, sizeof(struct sockaddr_in));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(PORT);server_addr.sin_addr.s_addr = inet_addr(IP);/* 向服務器發送連接請求 */if (connect(client_sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr_in)) < 0) {perror("connect error");exit(1);}printf("[client] Connect successfully.\n");while (1) {/* 向服務器發送消息 */printf("[client] Please input your message>>>");memset(buffer, 0, MAX_SIZE);scanf("%[^\n]%*c", buffer);if (!buffer[0]) break;//輸入空代表結束通信send(client_sockfd, buffer, strlen(buffer), 0);/* 接收服務端的消息 */memset(buffer, 0, MAX_SIZE);recv(client_sockfd, buffer, sizeof(buffer), 0);printf("[client] Server's message:%s\n", buffer);}/* 關閉連接 */shutdown(client_sockfd, SHUT_RDWR);return 0; }

    運行結果


    十六、并發服務器模型(TCP多進程)

    服務端 server.c

    #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <errno.h>#include <stdio.h> #include <stdlib.h> #include <string.h>#define SERVER_PORT 1521 #define IP "0.0.0.0" #define MAX_SIZE 1024int main() {int server_sockfd;//服務器套接字描述符int client_sockfd;//通信套接字描述符struct sockaddr_in server_addr;//服務器套接字信息struct sockaddr_in client_addr;//客戶端套接字信息/* 獲取服務器套接字文件描述符 */server_sockfd = socket(AF_INET, SOCK_STREAM, 0);if (server_sockfd == -1) {perror("socket error");exit(1);}/* 初始化服務器套接字信息 */memset(&server_addr, 0, sizeof(struct sockaddr_in));server_addr.sin_family = AF_INET;//使用IPv4server_addr.sin_port = htons(SERVER_PORT);//對端口進行字節序轉化server_addr.sin_addr.s_addr = inet_addr(IP);//對IP地址進行格式轉化/* 因為最后需要服務器主動關閉連接,所以要設置服務器套接字為可重用 */int option = 1;setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));/* 綁定服務器套接字信息 */if (bind(server_sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr_in)) < 0) {perror("bind error");exit(1);}/* 將服務器套接字轉化為被動監聽 */if (listen(server_sockfd, 3) < 0) {perror("listen error!");exit(1);}/* 與客戶端進行串行連接 */while(1) {printf("[server] Server is waiting······\n");/* 等待客戶端的連接 */int len = sizeof(struct sockaddr_in);//通信套接字結構體長度memset(&client_addr, 0, sizeof(struct sockaddr_in));if ((client_sockfd = accept(server_sockfd, (struct sockaddr *)(&client_addr), &len)) < 0) {perror("accept error");exit(1);}printf("[server] Client %d port is %d, ip is %s.\n", client_sockfd,ntohs(client_addr.sin_port), inet_ntoa(client_addr.sin_addr));int pid = fork();//創建子進程用于收發消息if (pid > 0) {close(client_sockfd);} else if (pid == 0) {char buffer[1024];while (1) {/* 接收客戶端的消息 */memset(buffer, 0, MAX_SIZE);if (recv(client_sockfd, buffer, sizeof(buffer), 0) == 0) {/* 監測客戶端的退出 */printf("[server] Client %d has exited.\n", client_sockfd);exit(0);}printf("[server] Client %d message:%s\n", client_sockfd, buffer);/* 向客戶端發送消息 */send(client_sockfd, "I have received your message.", 30, 0);}} else {perror("fork error");exit(1);}}return 0; }

    客戶端 client.c

    #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <errno.h>#include <stdio.h> #include <stdlib.h> #include <string.h>#define PORT 1521 #define IP "120.78.188.0" #define MAX_SIZE 1024int main() {int client_sockfd;//客戶端套接字描述符char buffer[MAX_SIZE];//收發數據緩沖區struct sockaddr_in server_addr;//服務器套接字描述符/* 獲取客戶端套接字文件描述符 */if((client_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {perror("socket error");exit(1);}/* 初始化服務器套接字信息 */memset(&server_addr, 0, sizeof(struct sockaddr_in));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(PORT);server_addr.sin_addr.s_addr = inet_addr(IP);/* 向服務器發送連接請求 */if (connect(client_sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr_in)) < 0) {perror("connect error");exit(1);}printf("[client] Connect successfully.\n");while (1) {/* 向服務器發送消息 */printf("[client] Please input your message>>>");memset(buffer, 0, MAX_SIZE);scanf("%[^\n]%*c", buffer);if (!buffer[0]) break;//輸入空代表結束通信send(client_sockfd, buffer, strlen(buffer), 0);/* 接收服務端的消息 */memset(buffer, 0, MAX_SIZE);recv(client_sockfd, buffer, sizeof(buffer), 0);printf("[client] Server's message:%s\n", buffer);}/* 關閉連接 */shutdown(client_sockfd, SHUT_RDWR);return 0; }

    運行結果

    總結

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

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