標籤:style blog io ar color os 使用 sp strong
功能:分為用戶端和伺服器,client可向server傳送字串,傳送檔案。
環境:Ubuntu
編譯方法: server.c: gcc –o server server.cclient.c: gcc -o client client.c
運行方法:開啟兩個終端,先在一個終端運行./ server,然後在另一個終端運行 ./client。
源碼:
server.c
#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<string.h>#include<sys/socket.h>#include<sys/stat.h>#include<arpa/inet.h>#define MAXBUF 256#define PORT 7787int main(){ int clen; int ssock,csock; struct sockaddr_in client_addr,server_addr;//用戶端,伺服器位址 char buf[MAXBUF+5], name[MAXBUF+5];//兩個緩衝區 FILE *fp; if((ssock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0) /* AF_UNIX表示只能夠用於單一的Unix 系統處理序間通訊,SOCK_STREAM表明用的是TCP 協議 成功時返迴文件描述符,失敗時返回-1 */ { perror("socket error:"); exit(1); } clen = sizeof(client_addr); memset(&server_addr,0,sizeof(server_addr)); /*將已開闢的server_addr的前sizeof(server_addr)個位元組設定為0 */ server_addr.sin_family =AF_INET; /*sin_family指代協議族,在socket編程中只能是AF_INET*/ server_addr.sin_addr.s_addr=htonl(INADDR_ANY); /*INADDR_ANY表示可以和任何的主機通訊*/ server_addr.sin_port=htons(PORT);/*sin_port儲存連接埠號碼*/ if(bind(ssock,(struct sockaddr *)&server_addr,sizeof(server_addr))<0){ /* 使用bind進行綁定連接埠: bind將本地的連接埠同socket返回的檔案描述符捆綁在一起. 成功是返回0,失敗返回-1 */ perror("bind error"); exit(1); } if(listen(ssock,8)<0){ /* listen(bind後的檔案描述符,最大請求排隊長度) listen函數將bind的檔案描述符變為監聽通訊端,成功返回0,否則返回-1 */ perror("listen error:"); exit(1); } csock=accept(ssock,(struct sockaddr *)&client_addr,(socklen_t*)&clen); /* accept(int sockfd, struct sockaddr *addr,int *addrlen) addr,addrlen是用來給用戶端的程式填寫的,伺服器端只要傳遞指標就可以了 accept成功時返回最後的伺服器端的檔案描述符,這個時候伺服器端可以向該描述符寫資訊了 失敗時返回-1 */ while(1){ if(recv(csock,buf, MAXBUF,MSG_WAITALL)>0) //MSG_WAITALL表示沒有讀到指定位元組數之前不返回 { if(strcmp(buf,"@#$%")==0){//表示要傳檔案 recv(csock,buf,MAXBUF,MSG_WAITALL);//接收檔案名 sprintf(name,"%s1",buf);//將buf格式化為長字串型,賦給name if((freopen(name,"w",stdout))!=NULL){//以寫方式開啟檔案 while(recv(csock,buf,MAXBUF,MSG_WAITALL)>0)//接收檔案內容 { if(strcmp(buf,"@#$%")==0)break;//收到@#$%表示已經傳送完畢 fwrite(buf,sizeof(char),strlen(buf),stdout);//寫入檔案 } fclose(stdout); freopen("/dev/tty","w",stdout);// puts("File received success!"); } } else if(strcmp(buf,"%$#@")==0){//表示傳字元 recv(csock,buf,MAXBUF,MSG_WAITALL);//接收傳來的字元 printf("%s\n",buf); send(csock,"Server receive message success!",MAXBUF,0);//返回確認資訊 } } } close(csock); return 0;}
client.c
#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<sys/socket.h>#include<sys/stat.h>#include<arpa/inet.h>#include<string.h>#define MAXBUF 256#define PORT 7787int main(){ int ssock; int clen, ch; char buf[MAXBUF+5];//緩衝區 struct sockaddr_in server_addr; if((ssock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0){ // 建立socket,使用網際網路,TCP流傳輸 perror("socket error:"); exit(1); } clen = sizeof(server_addr); memset(&server_addr,0,sizeof(server_addr)); server_addr.sin_family =AF_INET; server_addr.sin_addr.s_addr=inet_addr("127.0.0.1"); //inet_addr:ip轉換為4位元組整形,使用時需要根據服務端ip變更 server_addr.sin_port =htons(PORT); if(connect(ssock,(struct sockaddr *)&server_addr,clen)<0){ /* 用戶端串連伺服器,參數依次為socket檔案描述符,地址資訊,地址結構大小, connect函數是用戶端用來同服務端串連的.成功時返回0, 失敗返回-1 */ perror("connect error:"); exit(1); } while(1) { printf("1: Send Message\n2: Send File\n3: Exit [1/2/3]?"); scanf("%d",&ch); if(ch==1){//Send Message scanf("%s",buf); send(ssock,"%$#@",MAXBUF,0);//告訴伺服器要傳字串 send(ssock, buf, MAXBUF,0);//發送要傳的字元 recv(ssock, buf, MAXBUF,MSG_WAITALL);//接收確認資訊 puts(buf); } else if(ch==2){//Send File printf("input the filename: "); scanf("%s",buf); if(freopen(buf, "r",stdin)!=NULL){ send(ssock,"@#$%",MAXBUF,0);//告訴伺服器要傳檔案 send(ssock,buf,MAXBUF,0);//傳檔案名稱 int cnt=0; while((ch=getchar())!=EOF){ buf[cnt++]=ch;//buf緩衝區大小為MAXBUF,也就是每讀MAXBUF個字元,傳送一次 if(cnt==MAXBUF){ buf[cnt]=0,cnt=0; send(ssock,buf,MAXBUF,0); } } if(cnt){buf[cnt]=0,cnt=0;send(ssock,buf,MAXBUF,0);}//傳送最後不足MAXBUF的部分 send(ssock,"@#$%",MAXBUF,0);//表示傳送完畢 fclose(stdin); freopen("/dev/tty","r",stdin); } } else break; } close(ssock); return 0;}
linux-socket編程(1)