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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

UNIX 网络编程

發(fā)布時間:2024/8/1 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 UNIX 网络编程 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

目錄

1 socket網(wǎng)絡(luò)編程步驟

1.1 服務(wù)器編程步驟

1.2 客戶端編程步驟

1.3 函數(shù)以及結(jié)構(gòu)解釋

2 基于TCP的一對多網(wǎng)絡(luò)編程

2.1 服務(wù)器編程步驟

2.2 客戶端編程

2.3 函數(shù)解釋

2.4 基于TCP的網(wǎng)絡(luò)聊天室

3 基于UDP的一對多編程

3.1 服務(wù)器編程步驟

3.2 客戶端編程步驟

3.3 UDP下的讀寫數(shù)據(jù)

3.4 函數(shù)解釋

3.5 基于UDP的時間服務(wù)器代碼


本文要講解Unix下的網(wǎng)絡(luò)編程,即socket編程,也稱為套接字編程。

Unix系統(tǒng)在網(wǎng)絡(luò)上功能十分強(qiáng)大,歷史悠久,因此有一個非常固定的套路,代碼比較僵化,沒有改變的余地。Socket編程主要包括兩個方面,一個是本地通信,即計算機(jī)內(nèi)部的進(jìn)程間的通信(IPC),這個本文不過多講解,主要集中在后面的內(nèi)容,網(wǎng)絡(luò)通信。

本文先介紹Unix網(wǎng)絡(luò)編程的基本框架,以及具體的函數(shù)用法、結(jié)構(gòu)體,然后分別介紹TCP網(wǎng)絡(luò)編程和UDP網(wǎng)絡(luò)編程。本文只介紹編程框架,而不會涉及具體的協(xié)議。

1 socket網(wǎng)絡(luò)編程步驟

網(wǎng)絡(luò)編程要考慮兩個方面:服務(wù)器端和客戶端,客戶端通過網(wǎng)絡(luò)與服務(wù)器端通信。

1.1 服務(wù)器編程步驟

1、調(diào)用函數(shù)socket(),用來創(chuàng)建socket描述符。

int fd=socket(AF_INET,SOCK_DGRAM,0);if(fd==-1)perror("socket"),exit(-1);

?

2、準(zhǔn)備通訊地址(三個結(jié)構(gòu)體),進(jìn)行數(shù)據(jù)交互。

struct sockaddr_in addr;addr.sin_family=AF_INET;addr.sin_port=htons(2222);//服務(wù)器的端口addr.sin_addr.s_addr=inet_addr("192.168.1.112");//服務(wù)器的ip地址

?

3、綁定通訊地址和socket描述符,函數(shù)bind()

int res=bind(fd,(struct sockaddr*)&addr,sizeof(addr));if(res==-1)perror("bind "),exit(-1);elseprintf("綁定成功\n");

?

4、讀寫描述符,和讀寫文件描述符一樣,函數(shù)read()/write()。

char buf[100]={};res=read(fd,buf,sizeof(buf));

?

5、使用函數(shù)close()關(guān)閉socket描述符。

close(fd);

1.2 客戶端編程步驟

1、調(diào)用函數(shù)socket(),用來創(chuàng)建socket描述符。

int fd=socket(AF_INET,SOCK_DGRAM,0);if(fd==-1)perror("socket "),exit(-1);

?

2、準(zhǔn)備通訊地址(三個結(jié)構(gòu)體),進(jìn)行數(shù)據(jù)交互。

struct sockaddr_in addr;addr.sin_family=AF_INET;addr.sin_port=htons(2222);//服務(wù)器addr.sin_addr.s_addr=inet_addr("192.168.1.112");

?

3、綁定通訊地址和socket描述符,函數(shù)connect()

int res=connect(fd,(struct sockaddr*)&addr,sizeof(addr));if(res==-1)perror("connect "),exit(-1);

?

4、讀寫描述符,和讀寫文件描述符一樣,函數(shù)read()/write()。

write(fd,"hello",5);

5、使用函數(shù)close()關(guān)閉socket描述符。

??? close(fd);

除了1.3的bind()換成connect()之外,其他的與服務(wù)器端一樣,而且connect()和bind()用法完全一樣。

1.3 函數(shù)以及結(jié)構(gòu)解釋

1、socket() 函數(shù)

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

參數(shù)解釋

domin用于選擇協(xié)議簇,可以選擇一下的宏:

AF_UNIX/AF_LOCAL/AF_FILE :本地通信

AF_INET : 網(wǎng)絡(luò)通信IPv4 (一般使用這個)

AF_INET6 :網(wǎng)絡(luò)通信IPv6

type 用于選擇通信的類型,主要包括:

SOCK_STREAM :數(shù)據(jù)流,用于TCP。

SOCK_DGRAM :數(shù)據(jù)報,用于UDP。

protocol參數(shù)本來應(yīng)該指定協(xié)議,但是由于協(xié)議已經(jīng)被前兩個參數(shù)確定了,所以直接將protocol給0即可,這是Unix網(wǎng)絡(luò)編程的僵化的體現(xiàn)。

如果函數(shù)執(zhí)行成功,返回socket描述符,失敗返回-1.

這個函數(shù)用來生成一個socket描述符。

2、結(jié)構(gòu)體

網(wǎng)絡(luò)通信需要三個結(jié)構(gòu)體來指定網(wǎng)絡(luò)信息,分別是struct sockaddr、struct sockaddr_un、struct sockaddr_in。其中sockaddr主要用于做函數(shù)的參數(shù),并不儲存數(shù)據(jù),即沒啥實際的用處,socjaddr_un負(fù)責(zé)存儲本地通信的地址數(shù)據(jù),sockaddr_in負(fù)責(zé)存儲網(wǎng)絡(luò)通信的地址數(shù)據(jù)。

#include <sys/un.h>struct sockaddr_un{int sun_family; //用于指定協(xié)議簇,和socket()要保持一致char sun_path[]; //存socket文件名,作為交互的媒介}#include<netinet/in.h>struct sockaddr_in{int sin_family; //用于指定協(xié)議簇,和socket()一致short sin_port; //端口號struct in_addr sin_addr; //存儲IP地址的結(jié)構(gòu)}

?

注:sockaddr_in / sockaddr_un 在做參數(shù)時必須類型轉(zhuǎn)換為sockaddr,讀寫數(shù)據(jù)時,一方讀數(shù)據(jù),另一方必須寫數(shù)據(jù)。

?

3、bind()

int bind(int sockfd , struct sockaddr* addr , socklen_t size);

參數(shù)解釋

sockfd是socket文件描述符,即socket()函數(shù)的返回值。

addr是通信地址的指針,需要做類型轉(zhuǎn)換

size是通信地址的大小,即sizeof(struct)。

這個函數(shù)用來綁定自己的IP地址和端口號

4、connect()

int connect(int sockfd , const struct sockaddr *addr , socklen_t addrlen);

參數(shù)解釋

sockfd是socket文件描述符,即socket()函數(shù)的返回值。

addr是通信地址的指針,需要做類型轉(zhuǎn)換

size是通信地址的大小,即sizeof(struct)。

TCP客戶通過connect函數(shù)與服務(wù)端進(jìn)行通信。

2 基于TCP的一對多網(wǎng)絡(luò)編程

所謂的一對多編程,即只有一個服務(wù)器,有很多個客戶端,現(xiàn)在基本都是一對多編程。TCP是一個基于連接的協(xié)議,在網(wǎng)絡(luò)交互中,服務(wù)器和客戶端要保持連接,不能斷開。如果出現(xiàn)數(shù)據(jù)錯誤,TCP會重新發(fā)送,保證數(shù)據(jù)的正確和完整,但是資源的消耗比較大。

2.1 服務(wù)器編程步驟

1、socket()得到一個socket描述符

2、準(zhǔn)備通信地址 struct sockaddr_in

3、綁定bind(),連接端口

4、監(jiān)聽函數(shù)listen(),這個函數(shù)用來控制同一時刻連接的人數(shù)。

5、等待客戶端的連接,函數(shù)accept(),返回一個新的socket描述符,這個新的socket描述符用于讀寫交互。

6、讀寫函數(shù)read()/write()

7、關(guān)閉socket()

2.2 客戶端編程

1、調(diào)用函數(shù)socket(),用來創(chuàng)建socket描述符。

2、準(zhǔn)備通訊地址(三個結(jié)構(gòu)體),進(jìn)行數(shù)據(jù)交互。

3、綁定通訊地址和socket描述符,函數(shù)connect()

4、讀寫描述符,和讀寫文件描述符一樣,函數(shù)read()/write()。

5、使用函數(shù)close()關(guān)閉socket描述符。

這里的步驟和上面的客戶端編程的步驟是一樣的

2.3 函數(shù)解釋

1、listen()

該函數(shù)主要用于設(shè)置當(dāng)有多個用戶請求時,放入等待隊列,等待隊列的最大長度就是listen設(shè)置的。

int listen( int sockfd , int backlog);

參數(shù)解釋

sockfd 是你要設(shè)置的socket描述符

backlog是隊列的最大長度

2、accept()

int accept(int fd , struct sockaddr *addr , socklen_t *len);

參數(shù)解釋

fd就是socket描述符

addr是一個結(jié)構(gòu)體指針,用于傳出客戶端的通信地址

len是一個傳入傳出參數(shù),傳入addr的真實長度,傳出接收到的客戶端的通信地址的真實長度。(一般是相同的)

返回:成功返回新的socket描述符,失敗返回-1.

2.4 基于TCP的網(wǎng)絡(luò)聊天室

1、服務(wù)端代碼

#include<stdio.h> #include<stdlib.h> #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> #include<unistd.h> #include<string.h> #include<pthread.h>int sockall[100]; //存放socket描述符的數(shù)組 int sum; //聊天室人數(shù)int socket_findsit(){for(int i=0;i<100;i++)if(!sockall[i])return i;return -1; }void* task_chat(void* p){int index=(int)p;int fd=sockall[index];char buf[100]={};char name[100]={};char news[200]={};int i=0;sum++;printf("聊天室人數(shù):%d\n",sum);/*讀取用戶的用戶名*/int res=read(fd,name,sizeof(name));printf("用戶%s進(jìn)入聊天室\n",name);/*進(jìn)入聊天環(huán)節(jié)*/while(1){res=read(fd,buf,sizeof(buf));if(res==0)break;if(!strcmp(buf,"bye")){printf("用戶%s退出聊天室\n",name);break;}sprintf(news,"%.*s:%.*s",strlen(name),name,strlen(buf),buf);for(i=0;i<100;i++){if(sockall[i])write(sockall[i],news,strlen(news));}memset(buf,0,strlen(buf));memset(news,0,strlen(news));}close(fd);sockall[index]=0;sum--;printf("聊天室人數(shù):%d\n",sum);return NULL; }int main(){pthread_t id;int fd=socket(AF_INET,SOCK_STREAM,0);//TCP協(xié)議if(fd==-1)perror("socket "),exit(-1);struct sockaddr_in addr;addr.sin_family=AF_INET; //協(xié)議簇addr.sin_port=htons(2222);addr.sin_addr.s_addr=inet_addr("192.168.1.112");/*防止復(fù)用*/int reuse=1;setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse));int res=bind(fd,(struct sockaddr*)&addr,sizeof(addr));if(res==-1)perror("bind "),exit(-1);printf("成功綁定端口\n");listen(fd,100);//設(shè)置等待隊列的長度int index;while(1){struct sockaddr_in from;socklen_t len=sizeof(from);int sockfd=accept(fd,(struct sockaddr*)&from,&len);index=socket_findsit();if(index!=-1){sockall[index]=sockfd;pthread_create(&id,0,task_chat,(void*)(index));}else{printf("聊天室人數(shù)已滿\n");}}}

?

?

2、客戶端代碼

#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> #include<string.h> #include<pthread.h> void* task_read(void*p){int fd=(int)p;char buf[200]={};while(1){read(fd,buf,sizeof(buf));printf("%s\n",buf);memset(buf,0,strlen(buf));} }int main(){pthread_t id;int fd=socket(AF_INET,SOCK_STREAM,0);if(fd==-1)perror("socket "),exit(-1);struct sockaddr_in addr;addr.sin_family=AF_INET;addr.sin_port=htons(2222);addr.sin_addr.s_addr=inet_addr("114.116.5.220");int res=connect(fd,(struct sockaddr*)&addr,sizeof(addr));if(res==-1)perror("connect "),exit(-1);printf("成功連接服務(wù)器!\n");char buf1[100]={};char buf2[100]={};printf("請輸入您的用戶名:\n");scanf("%s",buf1);write(fd,buf1,strlen(buf1));memset(buf1,0,sizeof(buf1));printf("歡迎來到聊天室!\n");pthread_create(&id,0,task_read,(void*)fd);while(1){scanf("%s",buf1);write(fd,buf1,strlen(buf1));if(!strcmp(buf1,"bye"))break;memset(buf1,0,strlen(buf1));}close(fd); }

?

?

3 基于UDP的一對多編程

UDP協(xié)議,用戶數(shù)據(jù)報協(xié)議,無需連接,消耗資源少,但是有可能出錯。

3.1 服務(wù)器編程步驟

1、socket(),得到socket描述符

2、準(zhǔn)備通信地址,strutc sockaddr_in

3、綁定bind()

4、讀寫

5、關(guān)閉描述符

?

3.2 客戶端編程步驟

1、socket(),得到socket描述符

2、準(zhǔn)備通信地址,strutc sockaddr_in

3、讀寫

4、關(guān)閉描述符

客戶端不需要綁定或者連接。

?

3.3 UDP下的讀寫數(shù)據(jù)

UDP協(xié)議下,使用的讀寫函數(shù)與TCP不同,在不連接的前提下,讀數(shù)據(jù)使用read()或者recvfrom(),read()只能讀數(shù)據(jù),不能讀對方發(fā)送方的通信地址,而recvfrom兩者皆可。寫數(shù)據(jù)使用sendto(),不能使用write()。

?

3.4 函數(shù)解釋

1、recvfrom()

size_t recvfrom( int fd , void *buf , size_t len , int flags , struct sockaddr *src_addr , socklen_t *addrlen);

參數(shù)解釋

fd 文件描述符,在這里就是socket描述符,buf是要將文件讀取進(jìn)的對象,len是讀取的長度,flags一般給0即可,src_addr是一個傳出參數(shù),用于接收發(fā)送方的通信地址,addrlen是一個傳入傳出參數(shù),傳入addr的真實長度,傳出接收到的客戶端的通信地址的真實長度。

2、sendto()

int sendto(int fd , void *addr , size_t len , int flag , struct sockaddr *addr , socklen_t addlen);

參數(shù)解釋

fd是文件描述符,addr是要寫入的內(nèi)容指針,len是要寫入的長度,addr 傳入數(shù)據(jù)接收方的通信地址,addrlen就是通信地址的長度。

返回:成功返回發(fā)送的字節(jié)數(shù),失敗返回-1。

?

3.5 基于UDP的時間服務(wù)器代碼

1、服務(wù)器代碼

#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> #include<time.h> #include<string.h>int main(){int fd=socket(AF_INET,SOCK_DGRAM,0);if(fd==-1)perror("socket "),exit(-1);struct sockaddr_in addr;addr.sin_family=AF_INET;addr.sin_port=htons(2222);addr.sin_addr.s_addr=inet_addr("192.168.1.112");int res=bind(fd,(struct sockaddr*)&addr,sizeof(addr));if(res==-1)perror("bind "),exit(-1);printf("bind ok\n");char buf[100]={};while(1){struct sockaddr_in from;socklen_t len=sizeof(from);res=recvfrom(fd,buf,sizeof(buf),0,(struct sockaddr*)&from,&len);pid_t pid=fork();if(!pid){time_t time1=time(NULL);struct tm* tm1=localtime(&time1);printf("讀到了%d字節(jié),內(nèi)容:%s\n",res,buf);memset(buf,0,sizeof(buf));sprintf(buf,"%d/%d/%d %d:%d:%d",tm1->tm_year+1900,tm1->tm_mon+1,tm1->tm_mday,tm1->tm_hour,tm1->tm_min,tm1->tm_sec);sendto(fd,buf,sizeof(buf),0,(struct sockaddr*)&from,len);exit(0);}} }

?

?

2、客戶端代碼

#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h>int main(){int fd=socket(AF_INET,SOCK_DGRAM,0);if(fd==-1)perror("socket "),exit(-1);struct sockaddr_in addr;addr.sin_family=AF_INET;addr.sin_port=htons(2222);addr.sin_addr.s_addr=inet_addr("192.168.1.112");sendto(fd,"hello",5,0,(struct sockaddr*)&addr,sizeof(addr));char buf[100]={};int res=read(fd,buf,sizeof(buf));printf("日期:%s\n",buf);close(fd);return 0; }

?

?

總結(jié)

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

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