【摘要】 介紹文件發送、文件接收、線處理服務器接收、獲取天氣預報等知識點。
任務1:網絡編程
1.1 練習題說明
1.?實現TCP服務器與TCP客戶端之間的基本通信,收發數據 (按照上課的思路流程看函數文檔)
2.?實現TCP服務器與TCP客戶端之間的文件傳輸。(單個文件傳輸)
驗證方式: (1) 同一臺電腦演示 (2)同桌之間演示
考慮的問題:
(1)?網絡的傳輸環境,考慮應答問題
(2)?數據丟包之后如何處理? 可以重發
(3)?超時處理
(4)?服務器與客戶端之間連接斷開處理。(客戶端和服務器兩邊都需要重新連接)
文件傳輸可以在廣告機中使用。
(5)?每個數據的單位: 分包發送
(擴展要求): 顯示接收進度百分比,顯示接收的文件名稱,推薦: 定義結構體(使用數據結構)
3.?(擴展)實現TCP服務器與TCP客戶端之間的目錄傳輸(一級目錄)。
4.?(擴展)實現網絡聊天室(模仿QQ群發送消息的效果)
(1)?加入進去的成員都是客戶端
(2)?服務器負責給各個客戶端轉發消
??一般情況下,推薦最大每次傳輸的字節數不超過1024字節。
(1)文件發送客戶端
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*
TCP客戶端:
1. sockt創建套接字
2. 連接服務器
*/
int socket_cfd; /*保存客戶端套接字*/
int main(int argc,char **argv)
{
if(argc!=4)
{
printf("./server <192.168.xx.xx 服務器的IP地址> <服務器端口號> <文件名稱>\n");
exit(-1);
}
FILE *file=fopen(argv[3],"wb");
if(file==NULL)
{
printf("文件創建失敗!");
exit(0);
}
int err; //存放返回值狀態
/*1. 創建套接字*/
socket_cfd=socket(AF_INET,SOCK_STREAM,0);
if(socket_cfd<0)
{
printf("服務器端創建失敗!\n");
exit(-1);
}
/*2.連接服務器*/
struct sockaddr_in ServerAddr;
ServerAddr.sin_family=AF_INET; //IPV4協議
ServerAddr.sin_port=htons(atoi(argv[2])); //服務器的端口號 最大值65535
ServerAddr.sin_addr.s_addr=inet_addr(argv[1]); //IP地址賦值
err=connect(socket_cfd,(const struct sockaddr *)&ServerAddr,sizeof(struct sockaddr));
if(err!=0)
{
printf("服務器連接失敗!\n");
exit(-1);
}
/*3. 收發數據: 接收服務器發送的數據*/
char rx_buff[100];
fd_set readfds; //存放讀事件
int data;
int ack=666;
while(1)
{
FD_ZERO(&readfds); //清空文件描述符
FD_SET(socket_cfd,&readfds); //添加需要監控的文件描述符
data=select(socket_cfd+1,&readfds,NULL,NULL,NULL);
if(data>0)
{
err=read(socket_cfd,rx_buff,100);
if(err==0 && data==1)
{
printf("服務器已經與客戶端斷開連接!\n");
break;
}
fwrite(rx_buff,1,err,file);//寫入數據
printf("客戶端成功接收%d個字節\n",err);
write(socket_cfd,&ack,4); //發送應答信號。
}
}
close(socket_cfd);
fclose(file);
return 0;
}
(2)文件發送客戶端
#include
#include
#include
#include
#include
#include
/*
TCP服務器:
1. sockt創建套接字
2. bind綁定端口
3. 設置監聽的數量
4. 等待客戶端連接
*/
int socket_sfd; /*保存了服務器端的套接字*/
int socket_cfd; /*已經連接成功的客戶端套接字*/
/*
服務器是發送端
*/
int main(int argc,char **argv)
{
if(argc!=4)
{
printf("./server <192.168.xx.xx 本地IP地址> <服務器端口號> \n");
exit(-1);
}
FILE *file=fopen(argv[3],"rb");
if(file==NULL)
{
printf("文件打開失敗!\n");
exit(0);
}
int err; //存放返回值狀態
/*1. 創建套接字*/
socket_sfd=socket(AF_INET,SOCK_STREAM,0);
if(socket_sfd<0)
{
printf("服務器端創建失敗!\n");
exit(-1);
}
/*2. 綁定端口*/
struct sockaddr_in ServerAddr;
ServerAddr.sin_family=AF_INET; //IPV4協議
ServerAddr.sin_port=htons(atoi(argv[2])); //服務器的端口號 最大值65535
ServerAddr.sin_addr.s_addr=inet_addr(argv[1]); //IP地址賦值
err=bind(socket_sfd,(const struct sockaddr *)&ServerAddr,sizeof(struct sockaddr));
if(err!=0)
{
printf("服務器端 端口綁定失敗!\n");
exit(-1);
}
/*3. 設置監聽的數量*/
listen(socket_sfd,10);
/*4. 等待客戶端連接*/
struct sockaddr_in ClientAddr; //存放已經連接成功客戶端信息
socklen_t addrlen=sizeof(struct sockaddr); //客戶端的地址長度
socket_cfd=accept(socket_sfd,(struct sockaddr *)&ClientAddr,&addrlen);
if(socket_cfd<0)
{
printf("服務器端,連接客戶端失敗!\r\n");
exit(-1);
}
/*打印一些客戶端的信息*/
printf("成功連接的客戶端端口號:%d\n",ntohs(ClientAddr.sin_port));
printf("成功連接的客戶端IP地址:%s\n",inet_ntoa(ClientAddr.sin_addr));
/*5. 收發數據 :服務器給客戶端發送10個字節的數據*/
char tx_buff[100];
int len;
int ack;
while(1)
{
len=fread(tx_buff,1,100,file);
printf("服務器成功發送:%d 字節\r\n",len);
err=write(socket_cfd,tx_buff,len);
while(1)
{
err=read(socket_cfd,&ack,4); //等待客戶端的應答
if(err>0&&ack==666)
{
break;
}
}
if(len!=100)break;
}
close(socket_sfd);
fclose(file);
return 0;
}
文件名稱>
任務2:線程編程
#include int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); Compile and link with -pthread. -lpthread |
理解: 一個線程就是一個while(1)。
[root@wbyq linux-share-dir]# gcc app.c /tmp/cccOs4TK.o: In function `main': app.c:(.text+0x69): undefined reference to `pthread_create' app.c:(.text+0x8d): undefined reference to `pthread_create' collect2: ld 返回 1 [root@wbyq linux-share-dir]# gcc app.c -lpthread |
練習:
1.?學習線程的基本使用
2.?實現一個服務器實現多個客戶端的連接,實現通信。
思路: 一個客戶端就是一個獨立的線程。
3.?擴展練習: 實現服務器同時對多個客戶端進行文件發送。
(1)?服務器連接上一個客戶端就創建一個線程。
(2)?線程的函數需要寫幾個? 1個
1個函數需要考慮的問題: 函數的可重入性能!
需要考慮到資源搶占! 使用信號量!
1.?CRC16、CRC32校驗、
2.?和校驗 ”abcd <校驗和>” -->和
3.?異或校驗。 (1) 文件加密解碼
(2) 不添加三個變量,將兩個變量的值交換
int a=666; int b=888;
4.?MD5值校驗。
客戶端:
#include
#include /* See NOTES */
#include
#include //使用大小端轉換函數. find /
#include
/*服務器端口號定義*/
#define P_host 8080
// ./app 192.168.18.3
/*TCP客戶端代碼*/
int main(int argc,char *argv[])
{
if(argc!=2)
{
printf("參數錯誤:./app <服務器IP地址>\n");
return -1;
}
int clientfd;
struct sockaddr_in server_address; //存放服務器的IP地址信息
memset(&server_address,0,sizeof(struct sockaddr_in)); //初始化內存空間
server_address.sin_family=AF_INET; //IPV4協議
server_address.sin_port=htons(P_host); //端口號賦值
server_address.sin_addr.s_addr=inet_addr(argv[1]); //本地IP地址
/*1 .創建套接字*/
clientfd=socket(AF_INET,SOCK_STREAM,0);
if(clientfd<0)
{
printf("客戶端網絡套接字創建失敗!\n");
return -1;
}
/*2. 連接服務器*/
if(connect(clientfd,(const struct sockaddr *)&server_address,sizeof(struct sockaddr))!=0)
{
printf("客戶端連接服務器失敗!\n");
return -1;
}
char buff[1024];
while(1)
{
gets(buff);
write(clientfd,buff,strlen(buff));
}
return 0;
}
服務器:
#include
#include /* See NOTES */
#include
#include //使用大小端轉換函數
#include
#include
#include
#include
#include
#include
//函數聲明
void *start_routine_1(void *dev);
void *start_routine_2(void *dev);
typedef void *(*start_routine) (void *);
start_routine fun[]={start_routine_1,start_routine_2};
pthread_t thread_id[2]; //存放線程的標識符
int clientfd[2]; //保存TCP客戶端的網絡套接字
struct sockaddr_in client_address[2]; //存放客戶端的信息
socklen_t address_len[2]; //存放客戶端結構體信息的長度
/*服務器端口號定義*/
#define P_host 8080
/*TCP服務器代碼*/
int main(int argc,char *argv[])
{
int socketfd;
struct sockaddr_in server_address; //存放服務器的IP地址信息
memset(&server_address,0,sizeof(struct sockaddr_in)); //初始化內存空間
memset(client_address,0,sizeof(struct sockaddr_in)*2); //初始化內存空間
server_address.sin_family=PF_INET; //IPV4協議
server_address.sin_port=htons(P_host); //端口號賦值
server_address.sin_addr.s_addr=INADDR_ANY; //本地IP地址
/*1 .創建套接字*/
socketfd=socket(PF_INET,SOCK_STREAM,0);
if(socketfd<0)
{
printf("服務器網絡套接字創建失敗!\n");
return -1;
}
/*2. 綁定端口,創建服務器*/
if(bind(socketfd,(const struct sockaddr *)&server_address,sizeof(struct sockaddr))!=0)
{
printf("服務器綁定端口失敗!\n");
return -1;
}
/*3. 設監聽的端口數量*/
if(listen(socketfd,10)!=0)
{
printf("服務器端口監聽失敗!\n");
return -1;
}
int i;
for(i=0;i<2;i++)
{
address_len[i]=sizeof(struct sockaddr); //計算結構體大小 20
/*4. 等待客戶端連接*/
if((clientfd[i]=accept(socketfd,(struct sockaddr *)&client_address[i],&address_len[i]))<0)
{
printf("等待客戶端連接失敗!\n");
break;
}
//創建線程
if(pthread_create(&thread_id[i],NULL,fun[i],NULL)!=0)
{
printf("線程_%d_創建失敗!\n",i);
}
}
while(1)
{
}
//阻塞方式等待線程的結束
pthread_join(thread_id[0],NULL);
pthread_join(thread_id[1],NULL);
return 0;
}
//線程1
void *start_routine_1(void *dev)
{
while(1)
{
printf("TCP客戶端1連接!\n");
sleep(2);
}
//終止線程
pthread_exit(NULL);
}
//線程2
void *start_routine_2(void *dev)
{
while(1)
{
printf("TCP客戶端2連接!\n");
sleep(2);
}
//終止線程
pthread_exit(NULL);
}
任務3:使用的網絡服務器接口
C語言:面向過程 、 面向對象
1.?車牌號識別
2.?二維碼生成
3.?獲取北京時間
獲取接口的網址:http://www.k780.com/
1.?調用網絡的接口的方式: (天氣預報)
curl http://api.k780.com:88/?app=weather.future'&'weaid=南昌 '&&'appkey=10003'&'sign=b59bc3ef6191eb9f747dd4e83c99f2a4'&'format=json >123.txt |
注意: &是特殊的符號,需要使用單引號或者雙引號括起來。
Curl: 命令行的瀏覽器。
2.?調用二維碼生成的接口
curl http://api.k780.com:88/?app=qr.get'&'data=www.wanbangee.com'&'level=L'&'size=6 >123.png |
?? 練習:
1.?天氣預報查詢
查詢的格式: ./app <城市的中文名稱>
2.?獲取北京標準時間,顯示出來
3.?二維碼生成創建 運行格式: ./app <生成的二維碼內容>
生成之后直接顯示在屏幕上??梢允褂胑og命令
4.?車牌號的識別
5.?調用百度地圖API接口 http://lbsyun.baidu.com/index.php?title=uri/api/web
-
服務器
+關注
關注
12文章
9308瀏覽量
86072 -
TCP
+關注
關注
8文章
1378瀏覽量
79309 -
文件
+關注
關注
1文章
570瀏覽量
24823
發布評論請先 登錄
相關推薦
評論