轉載:http://blog.csdn.net/ljd_1986413/article/details/7940938
服務器程序和客戶端程序應當分別運行在兩臺計算機上。
在運行服務器端的計算機終端執行:./file_server
在運行客戶端的計算終端上執行:./file_client?? ipaddr_server
然后根據提示輸入要傳輸的服務器上的文件,該文件必須在服務器的當前運行目錄中,否則會提示找不到文件。
?
直接上源碼吧:
?
[cpp]?view plaincopy
- ??
- //?file_server.c?--?socket文件傳輸服務器端示例代碼???
- //?/??
- #include<netinet/in.h>???
- #include<sys/types.h>???
- #include<sys/socket.h>???
- #include<stdio.h>???
- #include<stdlib.h>???
- #include<string.h>???
- ??
- #define?HELLO_WORLD_SERVER_PORT????6666??
- #define?LENGTH_OF_LISTEN_QUEUE?????20??
- #define?BUFFER_SIZE????????????????1024??
- #define?FILE_NAME_MAX_SIZE?????????512??
- ??
- int?main(int?argc,?char?**argv)??
- {??
- ????//?set?socket's?address?information???
- ????//?設置一個socket地址結構server_addr,代表服務器internet的地址和端口??
- ????struct?sockaddr_in???server_addr;??
- ????bzero(&server_addr,?sizeof(server_addr));??
- ????server_addr.sin_family?=?AF_INET;??
- ????server_addr.sin_addr.s_addr?=?htons(INADDR_ANY);??
- ????server_addr.sin_port?=?htons(HELLO_WORLD_SERVER_PORT);??
- ??
- ????//?create?a?stream?socket???
- ????//?創建用于internet的流協議(TCP)socket,用server_socket代表服務器向客戶端提供服務的接口??
- ????int?server_socket?=?socket(PF_INET,?SOCK_STREAM,?0);??
- ????if?(server_socket?<?0)??
- ????{??
- ????????printf("Create?Socket?Failed!\n");??
- ????????exit(1);??
- ????}??
- ??
- ????//?把socket和socket地址結構綁定???
- ????if?(bind(server_socket,?(struct?sockaddr*)&server_addr,?sizeof(server_addr)))??
- ????{??
- ????????printf("Server?Bind?Port:?%d?Failed!\n",?HELLO_WORLD_SERVER_PORT);??
- ????????exit(1);??
- ????}??
- ??
- ????//?server_socket用于監聽???
- ????if?(listen(server_socket,?LENGTH_OF_LISTEN_QUEUE))??
- ????{??
- ????????printf("Server?Listen?Failed!\n");??
- ????????exit(1);??
- ????}??
- ??
- ????//?服務器端一直運行用以持續為客戶端提供服務???
- ????while(1)??
- ????{??
- ????????//?定義客戶端的socket地址結構client_addr,當收到來自客戶端的請求后,調用accept??
- ????????//?接受此請求,同時將client端的地址和端口等信息寫入client_addr中??
- ????????struct?sockaddr_in?client_addr;??
- ????????socklen_t??????????length?=?sizeof(client_addr);??
- ??
- ????????//?接受一個從client端到達server端的連接請求,將客戶端的信息保存在client_addr中??
- ????????//?如果沒有連接請求,則一直等待直到有連接請求為止,這是accept函數的特性,可以??
- ????????//?用select()來實現超時檢測???
- ????????//?accpet返回一個新的socket,這個socket用來與此次連接到server的client進行通信??
- ????????//?這里的new_server_socket代表了這個通信通道??
- ????????int?new_server_socket?=?accept(server_socket,?(struct?sockaddr*)&client_addr,?&length);??
- ????????if?(new_server_socket?<?0)??
- ????????{??
- ????????????printf("Server?Accept?Failed!\n");??
- ????????????break;??
- ????????}??
- ??
- ????????char?buffer[BUFFER_SIZE];??
- ????????bzero(buffer,?sizeof(buffer));??
- ????????length?=?recv(new_server_socket,?buffer,?BUFFER_SIZE,?0);??
- ????????if?(length?<?0)??
- ????????{??
- ????????????printf("Server?Recieve?Data?Failed!\n");??
- ????????????break;??
- ????????}??
- ??
- ????????char?file_name[FILE_NAME_MAX_SIZE?+?1];??
- ????????bzero(file_name,?sizeof(file_name));??
- ????????strncpy(file_name,?buffer,??
- ????????????????strlen(buffer)?>?FILE_NAME_MAX_SIZE???FILE_NAME_MAX_SIZE?:?strlen(buffer));??
- ??
- ????????FILE?*fp?=?fopen(file_name,?"r");??
- ????????if?(fp?==?NULL)??
- ????????{??
- ????????????printf("File:\t%s?Not?Found!\n",?file_name);??
- ????????}??
- ????????else??
- ????????{??
- ????????????bzero(buffer,?BUFFER_SIZE);??
- ????????????int?file_block_length?=?0;??
- ????????????while(?(file_block_length?=?fread(buffer,?sizeof(char),?BUFFER_SIZE,?fp))?>?0)??
- ????????????{??
- ????????????????printf("file_block_length?=?%d\n",?file_block_length);??
- ??
- ????????????????//?發送buffer中的字符串到new_server_socket,實際上就是發送給客戶端??
- ????????????????if?(send(new_server_socket,?buffer,?file_block_length,?0)?<?0)??
- ????????????????{??
- ????????????????????printf("Send?File:\t%s?Failed!\n",?file_name);??
- ????????????????????break;??
- ????????????????}??
- ??
- ????????????????bzero(buffer,?sizeof(buffer));??
- ????????????}??
- ????????????fclose(fp);??
- ????????????printf("File:\t%s?Transfer?Finished!\n",?file_name);??
- ????????}??
- ??
- ????????close(new_server_socket);??
- ????}??
- ??
- ????close(server_socket);??
- ??
- ????return?0;??
- }??
[cpp]?view plain?copy
- ??
- //?file_server.c?--?socket文件傳輸服務器端示例代碼??
- //?/??
- #include<netinet/in.h>??
- #include<sys/types.h>??
- #include<sys/socket.h>??
- #include<stdio.h>??
- #include<stdlib.h>??
- #include<string.h>??
- ??
- #define?HELLO_WORLD_SERVER_PORT????6666??
- #define?LENGTH_OF_LISTEN_QUEUE?????20??
- #define?BUFFER_SIZE????????????????1024??
- #define?FILE_NAME_MAX_SIZE?????????512??
- ??
- int?main(int?argc,?char?**argv)??
- {??
- ????//?set?socket's?address?information??
- ????//?設置一個socket地址結構server_addr,代表服務器internet的地址和端口??
- ????struct?sockaddr_in???server_addr;??
- ????bzero(&server_addr,?sizeof(server_addr));??
- ????server_addr.sin_family?=?AF_INET;??
- ????server_addr.sin_addr.s_addr?=?htons(INADDR_ANY);??
- ????server_addr.sin_port?=?htons(HELLO_WORLD_SERVER_PORT);??
- ??
- ????//?create?a?stream?socket??
- ????//?創建用于internet的流協議(TCP)socket,用server_socket代表服務器向客戶端提供服務的接口??
- ????int?server_socket?=?socket(PF_INET,?SOCK_STREAM,?0);??
- ????if?(server_socket?<?0)??
- ????{??
- ????????printf("Create?Socket?Failed!\n");??
- ????????exit(1);??
- ????}??
- ??
- ????//?把socket和socket地址結構綁定??
- ????if?(bind(server_socket,?(struct?sockaddr*)&server_addr,?sizeof(server_addr)))??
- ????{??
- ????????printf("Server?Bind?Port:?%d?Failed!\n",?HELLO_WORLD_SERVER_PORT);??
- ????????exit(1);??
- ????}??
- ??
- ????//?server_socket用于監聽??
- ????if?(listen(server_socket,?LENGTH_OF_LISTEN_QUEUE))??
- ????{??
- ????????printf("Server?Listen?Failed!\n");??
- ????????exit(1);??
- ????}??
- ??
- ????//?服務器端一直運行用以持續為客戶端提供服務??
- ????while(1)??
- ????{??
- ????????//?定義客戶端的socket地址結構client_addr,當收到來自客戶端的請求后,調用accept??
- ????????//?接受此請求,同時將client端的地址和端口等信息寫入client_addr中??
- ????????struct?sockaddr_in?client_addr;??
- ????????socklen_t??????????length?=?sizeof(client_addr);??
- ??
- ????????//?接受一個從client端到達server端的連接請求,將客戶端的信息保存在client_addr中??
- ????????//?如果沒有連接請求,則一直等待直到有連接請求為止,這是accept函數的特性,可以??
- ????????//?用select()來實現超時檢測??
- ????????//?accpet返回一個新的socket,這個socket用來與此次連接到server的client進行通信??
- ????????//?這里的new_server_socket代表了這個通信通道??
- ????????int?new_server_socket?=?accept(server_socket,?(struct?sockaddr*)&client_addr,?&length);??
- ????????if?(new_server_socket?<?0)??
- ????????{??
- ????????????printf("Server?Accept?Failed!\n");??
- ????????????break;??
- ????????}??
- ??
- ????????char?buffer[BUFFER_SIZE];??
- ????????bzero(buffer,?sizeof(buffer));??
- ????????length?=?recv(new_server_socket,?buffer,?BUFFER_SIZE,?0);??
- ????????if?(length?<?0)??
- ????????{??
- ????????????printf("Server?Recieve?Data?Failed!\n");??
- ????????????break;??
- ????????}??
- ??
- ????????char?file_name[FILE_NAME_MAX_SIZE?+?1];??
- ????????bzero(file_name,?sizeof(file_name));??
- ????????strncpy(file_name,?buffer,??
- ????????????????strlen(buffer)?>?FILE_NAME_MAX_SIZE???FILE_NAME_MAX_SIZE?:?strlen(buffer));??
- ??
- ????????FILE?*fp?=?fopen(file_name,?"r");??
- ????????if?(fp?==?NULL)??
- ????????{??
- ????????????printf("File:\t%s?Not?Found!\n",?file_name);??
- ????????}??
- ????????else??
- ????????{??
- ????????????bzero(buffer,?BUFFER_SIZE);??
- ????????????int?file_block_length?=?0;??
- ????????????while(?(file_block_length?=?fread(buffer,?sizeof(char),?BUFFER_SIZE,?fp))?>?0)??
- ????????????{??
- ????????????????printf("file_block_length?=?%d\n",?file_block_length);??
- ??
- ????????????????//?發送buffer中的字符串到new_server_socket,實際上就是發送給客戶端??
- ????????????????if?(send(new_server_socket,?buffer,?file_block_length,?0)?<?0)??
- ????????????????{??
- ????????????????????printf("Send?File:\t%s?Failed!\n",?file_name);??
- ????????????????????break;??
- ????????????????}??
- ??
- ????????????????bzero(buffer,?sizeof(buffer));??
- ????????????}??
- ????????????fclose(fp);??
- ????????????printf("File:\t%s?Transfer?Finished!\n",?file_name);??
- ????????}??
- ??
- ????????close(new_server_socket);??
- ????}??
- ??
- ????close(server_socket);??
- ??
- ????return?0;??
- }??
?
[cpp]?view plaincopyprint?
- //??
- //?file_client.c??socket傳輸文件的client端示例程序???
- //?///??
- #include<netinet/in.h>?????????????????????????//?for?sockaddr_in??
- #include<sys/types.h>??????????????????????????//?for?socket??
- #include<sys/socket.h>?????????????????????????//?for?socket??
- #include<stdio.h>??????????????????????????????//?for?printf??
- #include<stdlib.h>?????????????????????????????//?for?exit??
- #include<string.h>?????????????????????????????//?for?bzero??
- ??
- #define?HELLO_WORLD_SERVER_PORT???????6666??
- #define?BUFFER_SIZE???????????????????1024??
- #define?FILE_NAME_MAX_SIZE????????????512??
- ??
- int?main(int?argc,?char?**argv)??
- {??
- ????if?(argc?!=?2)??
- ????{??
- ????????printf("Usage:?./%s?ServerIPAddress\n",?argv[0]);??
- ????????exit(1);??
- ????}??
- ??
- ????//?設置一個socket地址結構client_addr,?代表客戶機的internet地址和端口??
- ????struct?sockaddr_in?client_addr;??
- ????bzero(&client_addr,?sizeof(client_addr));??
- ????client_addr.sin_family?=?AF_INET;?//?internet協議族??
- ????client_addr.sin_addr.s_addr?=?htons(INADDR_ANY);?//?INADDR_ANY表示自動獲取本機地址??
- ????client_addr.sin_port?=?htons(0);?//?auto?allocated,?讓系統自動分配一個空閑端口??
- ??
- ????//?創建用于internet的流協議(TCP)類型socket,用client_socket代表客戶端socket??
- ????int?client_socket?=?socket(AF_INET,?SOCK_STREAM,?0);??
- ????if?(client_socket?<?0)??
- ????{??
- ????????printf("Create?Socket?Failed!\n");??
- ????????exit(1);??
- ????}??
- ??
- ????//?把客戶端的socket和客戶端的socket地址結構綁定???
- ????if?(bind(client_socket,?(struct?sockaddr*)&client_addr,?sizeof(client_addr)))??
- ????{??
- ????????printf("Client?Bind?Port?Failed!\n");??
- ????????exit(1);??
- ????}??
- ??
- ????//?設置一個socket地址結構server_addr,代表服務器的internet地址和端口??
- ????struct?sockaddr_in??server_addr;??
- ????bzero(&server_addr,?sizeof(server_addr));??
- ????server_addr.sin_family?=?AF_INET;??
- ??
- ????//?服務器的IP地址來自程序的參數???
- ????if?(inet_aton(argv[1],?&server_addr.sin_addr)?==?0)??
- ????{??
- ????????printf("Server?IP?Address?Error!\n");??
- ????????exit(1);??
- ????}??
- ??
- ????server_addr.sin_port?=?htons(HELLO_WORLD_SERVER_PORT);??
- ????socklen_t?server_addr_length?=?sizeof(server_addr);??
- ??
- ????//?向服務器發起連接請求,連接成功后client_socket代表客戶端和服務器端的一個socket連接??
- ????if?(connect(client_socket,?(struct?sockaddr*)&server_addr,?server_addr_length)?<?0)??
- ????{??
- ????????printf("Can?Not?Connect?To?%s!\n",?argv[1]);??
- ????????exit(1);??
- ????}??
- ??
- ????char?file_name[FILE_NAME_MAX_SIZE?+?1];??
- ????bzero(file_name,?sizeof(file_name));??
- ????printf("Please?Input?File?Name?On?Server.\t");??
- ????scanf("%s",?file_name);??
- ??
- ????char?buffer[BUFFER_SIZE];??
- ????bzero(buffer,?sizeof(buffer));??
- ????strncpy(buffer,?file_name,?strlen(file_name)?>?BUFFER_SIZE???BUFFER_SIZE?:?strlen(file_name));??
- ????//?向服務器發送buffer中的數據,此時buffer中存放的是客戶端需要接收的文件的名字??
- ????send(client_socket,?buffer,?BUFFER_SIZE,?0);??
- ??
- ????FILE?*fp?=?fopen(file_name,?"w");??
- ????if?(fp?==?NULL)??
- ????{??
- ????????printf("File:\t%s?Can?Not?Open?To?Write!\n",?file_name);??
- ????????exit(1);??
- ????}??
- ??
- ????//?從服務器端接收數據到buffer中???
- ????bzero(buffer,?sizeof(buffer));??
- ????int?length?=?0;??
- ????while(length?=?recv(client_socket,?buffer,?BUFFER_SIZE,?0))??
- ????{??
- ????????if?(length?<?0)??
- ????????{??
- ????????????printf("Recieve?Data?From?Server?%s?Failed!\n",?argv[1]);??
- ????????????break;??
- ????????}??
- ??
- ????????int?write_length?=?fwrite(buffer,?sizeof(char),?length,?fp);??
- ????????if?(write_length?<?length)??
- ????????{??
- ????????????printf("File:\t%s?Write?Failed!\n",?file_name);??
- ????????????break;??
- ????????}??
- ????????bzero(buffer,?BUFFER_SIZE);??
- ????}??
- ??
- ????printf("Recieve?File:\t?%s?From?Server[%s]?Finished!\n",?file_name,?argv[1]);??
- ??
- ????//?傳輸完畢,關閉socket???
- ????fclose(fp);??
- ????close(client_socket);??
- ????return?0;??
- ??
- }??
客戶端不一定要bind(),服務端一定要bind(),為什么?不然客戶端怎么知道服務器位置(IP+PORT)。 一般客戶端不綁定端口,因為客戶程序經常開關, 由于一些原因(這里我說不清楚,你碰到了自然理解), 斷開時端口很少立刻釋放(一般要1、2分鐘)。 所以客戶端綁定端口容易出問題。?
注:服務器綁定的是偵聽端口,客戶連接后,? 新分配一個sock和它連接(這個sock的port是不同的,相當于沒有bind的一個端口)? 由于偵聽端口是沒有實際聯接的,所以斷開時不需握手,也就沒有釋放問題了。???(注這段是回答時突然想到的,自我感覺是正確的,大家來批判啊)