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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

C语言实现socket网络编程及多线程编程

發(fā)布時(shí)間:2023/12/10 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C语言实现socket网络编程及多线程编程 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 一.概述
  • 二.TCP socket網(wǎng)絡(luò)編程
    • 1.server端程序?qū)崿F(xiàn)(tcp_server.cpp)
    • 2.client端程序?qū)崿F(xiàn)(tcp_client.cpp)
    • 3.編譯與執(zhí)行
  • 三.UDP socket網(wǎng)絡(luò)編程
    • 1.server端程序?qū)崿F(xiàn)(udp_server.cpp)
    • 2.client端程序?qū)崿F(xiàn)(udp_client.cpp)
    • 3.編譯與執(zhí)行

一.概述

??socket網(wǎng)絡(luò)編程在網(wǎng)絡(luò)通信中至關(guān)重要,因此本文結(jié)合socket網(wǎng)絡(luò)編程和linux多線程編程在linux環(huán)境下實(shí)現(xiàn)網(wǎng)絡(luò)通信。實(shí)現(xiàn)思路大致如下:server服務(wù)端監(jiān)聽(tīng)某個(gè)socket端口等待客戶端client連接,在客戶端連接成功后創(chuàng)建一個(gè)線程(pthread_create)來(lái)處理該連接,在主線程中監(jiān)聽(tīng)客戶端的連接,在子線程中處理每個(gè)socket連接。

二.TCP socket網(wǎng)絡(luò)編程

1.server端程序?qū)崿F(xiàn)(tcp_server.cpp)

#include <stdio.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> #include <arpa/inet.h> #include <string.h> #include <iostream> #include <pthread.h> //使用多線程頭文件 #include <netinet/in.h>using namespace std; //使用標(biāo)準(zhǔn)空間//注意:在socket服務(wù)器編程當(dāng)中有多個(gè)文件描述符 //其中socket返回的文件描述符sockfd是用來(lái)監(jiān)聽(tīng)用的,不能讀寫,而accept返回的文件描述符clifd是用來(lái)連接的操作的文件描述符。可以讀寫操作 /* //sockaddr_in結(jié)構(gòu)體(用來(lái)管理server或者client的socket信息)定義: struct sockaddr_in{__SOCKADDR_COMMON (sin_); //ipv4 or ipv6in_port_t sin_port; //Port number.struct in_addr sin_addr; //Internet address.// Pad to size of `struct sockaddr'. unsigned char sin_zero[sizeof (struct sockaddr) -__SOCKADDR_COMMON_SIZE -sizeof (in_port_t) -sizeof (struct in_addr)];}; */ #define SERV_PORT 8010 //服務(wù)器端口 #define SERV_ADDR "192.168.1.23" //服務(wù)器ip #define BACKLOG 100 //服務(wù)器最多可以監(jiān)聽(tīng)的客戶端數(shù)量(最多排隊(duì)數(shù)量)int client_num = 0; //連接的客戶端計(jì)數(shù)//線程1處理函數(shù) void *client_func1(void *clifd_recv) {int ret = -1;char recv_buf[200]; //定義接收緩存區(qū)char send_buf[200]; //定義發(fā)送緩存區(qū)int clifd = *(int *)clifd_recv; //創(chuàng)建新線程首先獲取傳入的客戶端描述符clifdprintf("有新的客戶端 %d 連接成功,子線程1開(kāi)始工作\r\n",clifd);//5.在連接成功后使用recv函數(shù)來(lái)接收數(shù)據(jù)//函數(shù)原型:ssize_t recv(int socket, void *buffer, size_t length, int flags);while(1){ret = recv(clifd, recv_buf, sizeof(recv_buf), 0); //接收客戶端發(fā)送來(lái)的數(shù)據(jù),注意此處使用的網(wǎng)絡(luò)描述符是clifdif(ret < 1){cout<<"客戶端 "<<clifd<<" 斷開(kāi)了連接"<<endl;cout<<"關(guān)閉連接并退出"<<endl;close(clifd); //關(guān)閉accept文件描述符clifdclient_num--; //當(dāng)前服務(wù)的客戶端數(shù)量加一pthread_exit(NULL); //退出當(dāng)前的線程}cout<<"收到客戶端 "<<clifd<<" 發(fā)送的數(shù)據(jù):len= "<<ret<<" buf= "<<recv_buf<<endl;memset(recv_buf,0,sizeof(recv_buf)); //清空接收緩存區(qū)//6.使用send函數(shù)發(fā)生數(shù)據(jù)strcpy(send_buf,"hello client1!");ret = send(clifd, send_buf, strlen(send_buf), 0);cout<<"發(fā)送了"<<ret<<"個(gè)數(shù)據(jù)"<<endl;memset(send_buf,0,sizeof(send_buf)); //清空接收緩存區(qū)} }//線程2處理函數(shù) void *client_func2(void *clifd_recv) {int ret = -1;char recv_buf[200]; //定義接收緩存區(qū)char send_buf[200]; //定義發(fā)送緩存區(qū)int clifd = *(int *)clifd_recv; //創(chuàng)建新線程首先獲取傳入的客戶端描述符clifdprintf("有新的客戶端 %d 連接成功,子線程2開(kāi)始工作\r\n",clifd);//5.在連接成功后使用recv函數(shù)來(lái)接收數(shù)據(jù)//函數(shù)原型:ssize_t recv(int socket, void *buffer, size_t length, int flags);while(1){ ret = recv(clifd, recv_buf, sizeof(recv_buf), 0); //接收客戶端發(fā)送來(lái)的數(shù)據(jù),注意此處使用的網(wǎng)絡(luò)描述符是clifdif(ret < 1){cout<<"客戶端 "<<clifd<<" 斷開(kāi)了連接"<<endl;cout<<"關(guān)閉連接并退出"<<endl;close(clifd); //關(guān)閉accept文件描述符clifdclient_num--; //當(dāng)前服務(wù)的客戶端數(shù)量加一pthread_exit(NULL); //退出當(dāng)前的線程}cout<<"收到客戶端 "<<clifd<<" 發(fā)送的數(shù)據(jù):len= "<<ret<<" buf= "<<recv_buf<<endl;memset(recv_buf,0,sizeof(recv_buf)); //清空接收緩存區(qū)//6.使用send函數(shù)發(fā)生數(shù)據(jù)strcpy(send_buf,"hello client2!!");ret = send(clifd, send_buf, strlen(send_buf), 0);cout<<"發(fā)送了"<<ret<<"個(gè)數(shù)據(jù)"<<endl;memset(send_buf,0,sizeof(send_buf)); //清空接收緩存區(qū)} }//線程3處理函數(shù) void *client_func3(void *clifd_recv) {int ret = -1;char recv_buf[200]; //定義接收緩存區(qū)char send_buf[200]; //定義發(fā)送緩存區(qū)int clifd = *(int *)clifd_recv; //創(chuàng)建新線程首先獲取傳入的客戶端描述符clifdprintf("有新的客戶端 %d 連接成功,子線程3開(kāi)始工作\r\n",clifd);//5.在連接成功后使用recv函數(shù)來(lái)接收數(shù)據(jù)//函數(shù)原型:ssize_t recv(int socket, void *buffer, size_t length, int flags);while(1){ ret = recv(clifd, recv_buf, sizeof(recv_buf), 0); //接收客戶端發(fā)送來(lái)的數(shù)據(jù),注意此處使用的網(wǎng)絡(luò)描述符是clifdif(ret < 1){cout<<"客戶端 "<<clifd<<" 斷開(kāi)了連接"<<endl;cout<<"關(guān)閉連接并退出"<<endl;close(clifd); //關(guān)閉accept文件描述符clifdclient_num--; //當(dāng)前服務(wù)的客戶端數(shù)量加一pthread_exit(NULL); //退出當(dāng)前的線程}cout<<"收到客戶端 "<<clifd<<" 發(fā)送的數(shù)據(jù):len= "<<ret<<" buf= "<<recv_buf<<endl;memset(recv_buf,0,sizeof(recv_buf)); //清空接收緩存區(qū)//6.使用send函數(shù)發(fā)生數(shù)據(jù)strcpy(send_buf,"hello client3!!!");ret = send(clifd, send_buf, strlen(send_buf), 0);cout<<"發(fā)送了"<<ret<<"個(gè)數(shù)據(jù)"<<endl;memset(send_buf,0,sizeof(send_buf)); //清空接收緩存區(qū)} }int main(int argc,char **argv) {int ret = -1;int sockfd = -1; //定義socket網(wǎng)絡(luò)文件描述符int clifd = -1; //定義accept網(wǎng)絡(luò)文件描述符pthread_t th = -1; //定義一個(gè)多線程創(chuàng)建句柄struct sockaddr_in servaddr={0}; //服務(wù)器sockaddr_in定義成ipv4類型的服務(wù)器ip結(jié)構(gòu)體(ipv6是sockaddr_inv6)struct sockaddr_in cliaddr={0}; //客戶端sockaddr_insocklen_t address_len = 0; //客戶端長(zhǎng)度//1.首先使用socket函數(shù)創(chuàng)建網(wǎng)絡(luò)文件描述符(類似于文件IO中的open函數(shù))//函數(shù)原型:int socket(int domain, int type, int protocol); sockfd = socket(AF_INET, SOCK_STREAM, 0); //ipv4,TCP,系統(tǒng)自動(dòng)選擇protocolif(sockfd < 0){cout<<"創(chuàng)建socket文件描述符失敗"<<endl;_exit(-1);}cout<<"sockfd="<<sockfd<<endl;//注意:由TCP套接字狀態(tài)TIME_WAIT引起在結(jié)束本次會(huì)話后close立刻開(kāi)啟下次會(huì)話會(huì)Bind失敗。//該狀態(tài)在套接字關(guān)閉后約保留 2 到 4 分鐘。在 TIME_WAIT 狀態(tài)退出之后,套接字被刪除,該地址才能被重新綁定而不出問(wèn)題。//因此下面兩句話的加入可以解決這個(gè)問(wèn)題int on = 1;ret = setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );//2.使用bind函數(shù)綁定socket文件描述符和相關(guān)參數(shù)//函數(shù)原型:int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen); servaddr.sin_family = AF_INET; //定義servaddr的domain地址族為ipv4servaddr.sin_port = htons(SERV_PORT); //定義servaddr的portnum為SERV_PORT(8010),host to net shortservaddr.sin_addr.s_addr = inet_addr(SERV_ADDR); //定義servaddr的address為SERV_ADDR(192.168.1.23) person----->u32//servaddr.sin_addr.s_addr = INADDR_ANY; //監(jiān)聽(tīng)該電腦的所有IPmemset(servaddr.sin_zero,0,sizeof(servaddr.sin_zero)); //設(shè)置servaddr的sin_zero區(qū)域?yàn)?ret = bind(sockfd, (const struct sockaddr *)&servaddr,sizeof(servaddr)); //使用bind函數(shù)綁定socket文件描述符和相關(guān)參數(shù)if(ret < 0){cout<<"bind函數(shù)綁定socket文件描述符失敗"<<endl;_exit(-1);}cout<<"bind綁定成功"<<endl;//3.使用listen函數(shù)進(jìn)行接收監(jiān)聽(tīng)(監(jiān)聽(tīng)當(dāng)前設(shè)置的ip地址下的端口號(hào)port)//函數(shù)原型:int listen(int socket, int backlog);ret = listen(sockfd, BACKLOG); //sockfd,等待列表,最多可以排隊(duì)排BACKLOG(100)個(gè)if(ret < 0){cout<<"listen監(jiān)聽(tīng)失敗"<<endl;_exit(-1);}cout<<"listen監(jiān)聽(tīng)成功,等待客戶端連接:"<<endl;while(1){//4.使用accept函數(shù)阻塞等待客戶端連接,注意:會(huì)阻塞!!!//函數(shù)原型:int accept(int socket, struct sockaddr *restrict address,socklen_t *restrict address_len);address_len = sizeof(struct sockaddr); //給client_len賦值clifd = accept(sockfd, (struct sockaddr *)&cliaddr,&address_len); //此時(shí)會(huì)阻塞在這監(jiān)聽(tīng)客戶端連接if(clifd < 0){cout<<"accept連接客戶端失敗"<<endl;_exit(-1);}cout<<"listen連接客戶端成功,clifd ="<<clifd<<endl;cout<<"客戶端端口號(hào)port= "<<ntohs(cliaddr.sin_port)<<endl;cout<<"客戶端ip= "<<inet_ntoa(cliaddr.sin_addr)<<endl;//在收到客戶端連接成功后創(chuàng)建一個(gè)新的線程,在線程里進(jìn)行數(shù)據(jù)收發(fā)client_num++; //當(dāng)前服務(wù)的客戶端數(shù)量加1switch(client_num){case 1:ret = pthread_create(&th, NULL, client_func1, (void *)(&clifd)); //創(chuàng)建一個(gè)線程client_func,將客戶端描述符clifd作為參數(shù)傳遞給多線程處理函數(shù)break;case 2:ret = pthread_create(&th, NULL, client_func2, (void *)(&clifd));break;case 3:ret = pthread_create(&th, NULL, client_func3, (void *)(&clifd));break;default:cout<<"連接的客戶端數(shù)量超過(guò)3臺(tái),停止服務(wù)"<<endl;break;}if(ret == 0){printf("創(chuàng)建線程 %d 成功,有新的客戶端 %d 連接成功,線程創(chuàng)建成功\r\n",(int)th,clifd);pthread_detach(th); //在線程創(chuàng)建成功后使用pthread_detach分離子線程,這樣就可以在子線程退出后自動(dòng)回收子線程資源了}else{printf("線程創(chuàng)建失敗\r\n");_exit(-1);}}cout<<"所有線程全部關(guān)閉,退出"<<endl;close(sockfd); //關(guān)閉socket文件描述符return 0; }

2.client端程序?qū)崿F(xiàn)(tcp_client.cpp)

#include <stdio.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> #include <arpa/inet.h> #include <string.h> #include <iostream>using namespace std; //使用標(biāo)準(zhǔn)空間 /* //sockaddr_in結(jié)構(gòu)體定義: struct sockaddr_in{__SOCKADDR_COMMON (sin_); //ipv4 or ipv6in_port_t sin_port; //Port number.struct in_addr sin_addr; //Internet address.// Pad to size of `struct sockaddr'. unsigned char sin_zero[sizeof (struct sockaddr) -__SOCKADDR_COMMON_SIZE -sizeof (in_port_t) -sizeof (struct in_addr)];}; */ #define SERV_PORT 8010 //服務(wù)器端口 #define SERV_ADDR "192.168.1.23" //服務(wù)器ip #define CLI_ADDR "192.168.1.50" //服務(wù)器開(kāi)放給我們的ip地址 char recv_buf[1000]; //定義接收緩存區(qū) char send_buf[1000]; //定義發(fā)送緩存區(qū) int main(int argc,char **argv) {int ret = -1;int sockfd = -1; //定義網(wǎng)絡(luò)文件描述符struct sockaddr_in servaddr={0}; //服務(wù)器sockaddr_in定義成ipv4類型的服務(wù)器ip結(jié)構(gòu)體(ipv6是sockaddr_inv6)//1.首先使用socket函數(shù)創(chuàng)建網(wǎng)絡(luò)文件描述符(類似于文件IO中的open函數(shù))//函數(shù)原型:int socket(int domain, int type, int protocol); sockfd = socket(AF_INET, SOCK_STREAM, 0); //ipv4,TCP,系統(tǒng)自動(dòng)選擇protocolif(sockfd < 0){cout<<"創(chuàng)建socket文件描述符失敗"<<endl;_exit(-1);}cout<<"sockfd="<<sockfd<<endl;//2.使用connect函數(shù)連接服務(wù)器//函數(shù)原型:int connect(int socket, const struct sockaddr *address,socklen_t address_len);servaddr.sin_family = AF_INET; //定義servaddr的domain地址族為ipv4servaddr.sin_port = htons(SERV_PORT); //定義servaddr的portnum為SERV_PORT(8010),host to net shortservaddr.sin_addr.s_addr = inet_addr(SERV_ADDR); //定義servaddr的address為SERV_ADDR(192.168.1.23) person----->u32ret = connect(sockfd, (const struct sockaddr *)&servaddr,sizeof(servaddr));if(ret < 0){cout<<"客戶端connect服務(wù)器失敗"<<endl;_exit(-1);}cout<<"客戶端connect服務(wù)器成功"<<endl;//下面客戶端和服務(wù)器互相收發(fā)while(1){//6.使用send函數(shù)發(fā)生數(shù)據(jù)cout<<"請(qǐng)輸入要發(fā)送給服務(wù)器的內(nèi)容:";cin >> send_buf;if(!strncmp(send_buf,"+++",3))break;ret = send(sockfd, send_buf, strlen(send_buf), 0);cout<<"發(fā)送了"<<ret<<"個(gè)數(shù)據(jù)"<<endl;memset(send_buf,0,sizeof(send_buf)); //清空接收緩存區(qū)ret = recv(sockfd, recv_buf, sizeof(recv_buf), 0); //接收客戶端發(fā)送來(lái)的數(shù)據(jù),注意此處使用的網(wǎng)絡(luò)描述符是clifdif(ret < 1){cout<<"服務(wù)器斷開(kāi)了連接"<<endl;break;}cout<<"收到服務(wù)器發(fā)送的數(shù)據(jù):len= "<<ret<<" buf= "<<recv_buf<<endl;memset(recv_buf,0,sizeof(recv_buf)); //清空接收緩存區(qū)}cout<<"關(guān)閉連接并退出"<<endl;close(sockfd); //關(guān)閉socket文件描述符return 0; }

3.編譯與執(zhí)行

g++ tcp_server.cpp -o server -pthread g++ tcp_client.cpp -o client #arm-linux-gnueabihf-g++ tcp_server.cpp -o server #arm-linux-gnueabihf-g++ tcp_client.cpp -o client 其中g(shù)++編譯器編譯出的文件在x86架構(gòu)處理器運(yùn)行,arm-linux-gnueabihf-g++編譯出的文件在ARM架構(gòu)處理器運(yùn)行。另注意用到多線程pthread時(shí)編譯需要鏈接pthread庫(kù)。 編譯完成后,先后運(yùn)行服務(wù)器程序./server和客戶端程序./client程序,進(jìn)行數(shù)據(jù)交互。

三.UDP socket網(wǎng)絡(luò)編程

1.server端程序?qū)崿F(xiàn)(udp_server.cpp)

#include <stdio.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> #include <arpa/inet.h> #include <string.h> #include <iostream> #include <netinet/in.h>using namespace std; //使用標(biāo)準(zhǔn)空間 //在使用UDP網(wǎng)絡(luò)編程的時(shí)候,由于UDP非面向連接,因此不需要listen和accept。因此可以簡(jiǎn)單總結(jié)UDP server端的程序編寫流程如下: //1.socket創(chuàng)建fd //2.bind綁定server端的socket信息 //3.直接調(diào)用recvfrom函數(shù)接收來(lái)自客戶端的消息,同時(shí)讀取客戶端的信息并保存在cliaddr結(jié)構(gòu)體中,以便下次發(fā)送消息的時(shí)候可以準(zhǔn)確找到對(duì)方 //4.調(diào)用sendto函數(shù)給客戶端返回信息,需要用到剛剛接收的cliaddr信息(因?yàn)榉?wù)器可能被多個(gè)客戶端連接,因此不知道發(fā)給誰(shuí),只能根據(jù)cliaddr信息使用sendto發(fā)送)#define SERV_PORT 8010 //服務(wù)器端口 #define SERV_ADDR "192.168.1.23" //服務(wù)器ip #define BACKLOG 100 //服務(wù)器最多可以監(jiān)聽(tīng)的客戶端數(shù)量(最多排隊(duì)數(shù)量)int main(int argc,char **argv) {int ret = -1;int sockfd = -1; //定義socket網(wǎng)絡(luò)文件描述符int recv_len; //接收數(shù)據(jù)長(zhǎng)度int send_len; //發(fā)送數(shù)據(jù)長(zhǎng)度char recv_buf[200]; //定義接收緩存區(qū)char send_buf[200]; //定義發(fā)送緩存區(qū)struct sockaddr_in servaddr={0}; //服務(wù)器sockaddr_in定義成ipv4類型的服務(wù)器ip結(jié)構(gòu)體(ipv6是sockaddr_inv6)struct sockaddr_in cliaddr={0}; //客戶端sockaddr_insocklen_t address_len = 0; //客戶端長(zhǎng)度//1.首先使用socket函數(shù)創(chuàng)建網(wǎng)絡(luò)文件描述符(類似于文件IO中的open函數(shù))//函數(shù)原型:int socket(int domain, int type, int protocol); sockfd = socket(AF_INET, SOCK_DGRAM, 0); //ipv4,UDP,系統(tǒng)自動(dòng)選擇protocolif(sockfd < 0){cout<<"創(chuàng)建socket文件描述符失敗"<<endl;_exit(-1);}cout<<"sockfd="<<sockfd<<endl;//注意:由TCP套接字狀態(tài)TIME_WAIT引起在結(jié)束本次會(huì)話后close立刻開(kāi)啟下次會(huì)話會(huì)Bind失敗。//該狀態(tài)在套接字關(guān)閉后約保留 2 到 4 分鐘。在 TIME_WAIT 狀態(tài)退出之后,套接字被刪除,該地址才能被重新綁定而不出問(wèn)題。//因此下面兩句話的加入可以解決這個(gè)問(wèn)題int on = 1;ret = setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );//2.使用bind函數(shù)綁定socket文件描述符和相關(guān)參數(shù)//函數(shù)原型:int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen); servaddr.sin_family = AF_INET; //定義servaddr的domain地址族為ipv4servaddr.sin_port = htons(SERV_PORT); //定義servaddr的portnum為SERV_PORT(8010),host to net shortservaddr.sin_addr.s_addr = inet_addr(SERV_ADDR); //定義servaddr的address為SERV_ADDR(192.168.1.23) person----->u32//servaddr.sin_addr.s_addr = INADDR_ANY; //監(jiān)聽(tīng)該電腦的所有IPmemset(servaddr.sin_zero,0,sizeof(servaddr.sin_zero)); //設(shè)置servaddr的sin_zero區(qū)域?yàn)?ret = bind(sockfd, (const struct sockaddr *)&servaddr,sizeof(servaddr)); //使用bind函數(shù)綁定socket文件描述符和相關(guān)參數(shù)if(ret < 0){cout<<"bind函數(shù)綁定socket文件描述符失敗"<<endl;_exit(-1);}cout<<"bind綁定成功"<<endl;while(1){//3.使用recvfrom函數(shù)接收客戶端發(fā)送的數(shù)據(jù),返回接收數(shù)據(jù)長(zhǎng)度//入口參數(shù):fd,reve_buf,recv_len,flag,clinet_addr,clinet_lenaddress_len = sizeof(struct sockaddr);recv_len = recvfrom(sockfd, recv_buf, sizeof(recv_buf),0,(struct sockaddr *)&cliaddr,&address_len);if(recv_len > 0) //判斷接收到的數(shù)據(jù)大于0{recv_buf[recv_len] = '\0'; //添加結(jié)束符cout<<"客戶端端口號(hào)port= "<<ntohs(cliaddr.sin_port)<<endl;cout<<"客戶端ip= "<<inet_ntoa(cliaddr.sin_addr)<<endl;printf("從客戶端接收到 %d 個(gè)數(shù)據(jù),數(shù)據(jù)是:%s\r\n",recv_len,recv_buf); //打印出接收到的數(shù)據(jù)memset(recv_buf,0,sizeof(recv_buf));}//4.使用sendto函數(shù)發(fā)生數(shù)據(jù)address_len = sizeof(struct sockaddr); //地址長(zhǎng)度strcpy(send_buf,"hello client!");send_len = sendto(sockfd, send_buf, strlen(send_buf), 0,(const struct sockaddr *)&cliaddr, address_len);if(send_len > 0){cout<<"發(fā)送了 "<<send_len<<" 個(gè)數(shù)據(jù)"<<endl;memset(send_buf,0,sizeof(send_buf)); //清空接收緩存區(qū)}}cout<<"關(guān)閉連接并退出"<<endl;close(sockfd); //關(guān)閉socket文件描述符return 0; }

2.client端程序?qū)崿F(xiàn)(udp_client.cpp)

#include <stdio.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> #include <arpa/inet.h> #include <string.h> #include <iostream>using namespace std; //使用標(biāo)準(zhǔn)空間//在使用UDP網(wǎng)絡(luò)編程的時(shí)候,由于UDP非面向連接。因此可以簡(jiǎn)單總結(jié)UDP client端的程序編寫流程如下: //1.socket創(chuàng)建fd //2.確定server的socket信息并寫入servaddr中 //3.直接調(diào)用sendto函數(shù)給服務(wù)器發(fā)送消息,其中要用到servaddr信息 //4.調(diào)用recv函數(shù)接收來(lái)自服務(wù)器的消息,(因?yàn)榭蛻舳酥婪?wù)器的信息,因此直接recv就可以,而不用recvfrom)#define SERV_PORT 8010 //服務(wù)器端口 #define SERV_ADDR "192.168.1.23" //服務(wù)器ip #define CLI_ADDR "192.168.1.50" //定義客戶端地址,一般用不到int main(int argc,char **argv) {int ret = -1;int sockfd = -1; //定義網(wǎng)絡(luò)文件描述符int address_len = 0; //目的的長(zhǎng)度struct sockaddr_in servaddr={0}; //用來(lái)存放服務(wù)器的socket相關(guān)信息int send_len; //發(fā)送數(shù)據(jù)長(zhǎng)度int recv_len; //接收數(shù)據(jù)長(zhǎng)度char recv_buf[1000]; //定義接收緩存區(qū)char send_buf[1000]; //定義發(fā)送緩存區(qū)//1.首先使用socket函數(shù)創(chuàng)建網(wǎng)絡(luò)文件描述符(類似于文件IO中的open函數(shù))//函數(shù)原型:int socket(int domain, int type, int protocol); sockfd = socket(AF_INET, SOCK_DGRAM, 0); //ipv4,UDP,系統(tǒng)自動(dòng)選擇protocolif(sockfd < 0){cout<<"創(chuàng)建socket文件描述符失敗"<<endl;_exit(-1);}cout<<"sockfd="<<sockfd<<endl;//2.然后確定server的socket信息并寫入servaddr中servaddr.sin_family = AF_INET; //定義servaddr的domain地址族為ipv4servaddr.sin_port = htons(SERV_PORT); //定義servaddr的portnum為SERV_PORT(8010),host to net shortservaddr.sin_addr.s_addr = inet_addr(SERV_ADDR); //定義servaddr的address為SERV_ADDR(192.168.1.23) person----->u32//下面客戶端和服務(wù)器互相收發(fā)while(1){cout<<"請(qǐng)輸入要發(fā)送給服務(wù)器的內(nèi)容:";cin >> send_buf;if(!strncmp(send_buf,"+++",3))break;//3.使用sendto函數(shù)給服務(wù)器發(fā)生數(shù)據(jù)//入口參數(shù):fd,send_buf,send_len,flag,server_addr,server_lenaddress_len = sizeof(struct sockaddr); //地址長(zhǎng)度send_len = sendto(sockfd, send_buf, strlen(send_buf), 0,(const struct sockaddr *)&servaddr, address_len);if(send_len > 0){cout<<"發(fā)送了 "<<send_len<<" 個(gè)數(shù)據(jù)"<<endl;memset(send_buf,0,sizeof(send_buf)); //清空接收緩存區(qū)}//4.使用recv函數(shù)接收來(lái)自服務(wù)器的數(shù)據(jù)ret = recv(sockfd, recv_buf, sizeof(recv_buf), 0); //接收客戶端發(fā)送來(lái)的數(shù)據(jù),注意此處使用的網(wǎng)絡(luò)描述符是clifdif(ret < 1){cout<<"服務(wù)器斷開(kāi)了連接"<<endl;break;}cout<<"收到服務(wù)器發(fā)送的數(shù)據(jù):len= "<<ret<<" buf= "<<recv_buf<<endl;memset(recv_buf,0,sizeof(recv_buf)); //清空接收緩存區(qū)}cout<<"關(guān)閉連接并退出"<<endl; //實(shí)際從未建立過(guò)連接close(sockfd); //關(guān)閉socket文件描述符return 0; }

3.編譯與執(zhí)行

g++ udp_server.cpp -o server g++ udp_client.cpp -o client #arm-linux-gnueabihf-g++ udp_server.cpp -o server #arm-linux-gnueabihf-g++ udp_client.cpp -o client 其中g(shù)++編譯器編譯出的文件在x86架構(gòu)處理器運(yùn)行,arm-linux-gnueabihf-g++編譯出的文件在ARM架構(gòu)處理器運(yùn)行。另注意用到多線程pthread時(shí)編譯需要鏈接pthread庫(kù)。

執(zhí)行說(shuō)明,由于UDP不面向連接,因此接收和發(fā)送的時(shí)候都需要知道對(duì)方的信息,而服務(wù)器可以接收多個(gè)客戶端的數(shù)據(jù),因此在執(zhí)行測(cè)試時(shí)可以打開(kāi)一個(gè)server程序和多個(gè)client程序,建立一對(duì)多的連接,且彼此之間交互互不影響。

總結(jié)

以上是生活随笔為你收集整理的C语言实现socket网络编程及多线程编程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。