問題描述:擬在服務器上利用c或c++來編寫服務器端程序,在android手機上編寫客戶端程序,實現通過手機客戶端來訪問服務器上的資源。由於在c中socket的使用方式跟Java中有一些不同,c中的使用方式比較麻煩,java中相對簡單。本文中服務器端的環境是linux。若是windows,C Socket的使用方式會稍有不同。
Socket介紹
Socket(套接字)相當於一種特殊的IO。只不過平常的IO兩端是程序(內存)和本地磁盤。而此處的兩端是網絡中的兩個程序。也可以將socket看成是在程序兩端建立起的一條管道,兩個程序通過這條管道來交換數據。
Java中Socket的使用方式:
服務器端:
1. ServerSocket server=newServerSocket(6000);//創建服務器端的socket,並綁定端口6000
2. Socket socket=Server.accept();//接受客戶端請求,並返回一個和客戶端通信的socket
3. Socket.getInputStream();//利用socket來返回輸入輸出流,以後便是java的IO操作
4. Socket.getOutputStream();
5. 可以將outputStream->outputStreamWriter->bufferedWriter->PrintWriter,最後利用printwriter的println(str)方法就可以向對方傳輸數據。此種方法相對於直接使用bufferedWriter的好處是,不需要強制刷新緩衝區,前者需調用flush()方法。
客戶端:
Socket socket=new socket(“202.118.18.3”,6000);//新建客戶端的同時,給定請求的主機地址和端口號,並想服務器端發送請求,返回一個socket來與服務器端進行通信。
C中socket的使用方式;
服務器端:
1. Int sfd= socket(int domain, inttype , int protocol);//創建一個socket,相當於是上文中的serversocket,並不是用來與客戶端通信的socket。
Domain:所使用的協議族,通常爲PF_INET,protocal family,指的是TCP/IP協議
Type: 套接字的類型,有三種:SOCK_STREAM、SOCK_DIAGRAM、SOCK_RAW
Protocol: 通常賦值爲0
2. 配置socket的相關信息,比如使用的地址協議,監聽的主機地址和端口號。
Bind(int sockfd, struct sockaddr * s_addr, int addrlen );//綁定失敗時,返回-1,成功返回0
Sockfd:待配置的socket描述符,由上述方法創建。
S_addr: 一個數據結構,指出綁定的地址,端口號等信息。通常用struct sockaddr_in類型來填充
structsockaddr_in {
short int sin_family; //地址協議,通常爲AF_INET
unsigned short int sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
};
addrlen: sockaddr的長度
3. 監聽客戶端的請求,listen(int sockfd, int backlong)//監聽成功返回0,否則返回-1
Sockfd: 服務器端的監聽socket描述符
Backlong: 客戶端請求隊列的最大長度
以上三步,完成了java中的第一句話的功能,即創建服務器端socket,綁定端口號,並監聽客戶端請求
4. 接受客戶端的請求,int sockConn = accept(int sockfd, struct sockaddr_in* cfd, intaddrlen)
Sockfd:服務器端用來監聽請求的socket描述符
Cfd: sockaddr_in類型的指針,用來保存客戶端的地址和端口信息,以便進一步通信
Addrlen:sockaddr_in類型的長度,此參數大小與前一個參數的類型保持一致
該函數會返回一個新的socket描述符,這個描述符用來與客戶端進程進行通信。
5. 通信的函數
發送數據 ssize_t write(int fd,const void *buf, size_t nbytes);
Fd:用來通信的socket描述符,即accpet得到的描述符
Buf :一個指針類型,可以指向任何類型,存儲着要發送的內容
nbytes: 字節數
該函數返回值是成功發送的字節數,否則返回-1
接受數據 ssize_t read(intfd,void *buf,size_t nbyte);
Fd同上
Buf:是用來存儲即將讀取的數據
Nbytes:如果傳過來的數據字節數小於該值,則全部讀入buf所指向的數組,否則,最大能讀取nbytes個,可循環讀取。該函數返回的是成功讀取的字節數,否則返回-1
6. Close(int cfd);關閉套接字描述符。
客戶端:
1. 創建socket,用來與服務器端進行通信
2. 請求與服務器端建立連接
Connect(int cfd, struct sockaddr * s_addr, int addrlen);
Cfd: 上一步生成的socket描述符,連接成功後,使用它與服務器端進行通信
S_addr:服務器端的主機地址和端口號
Addrlen:sockaddr的長度
該函數成功返回0,否則返回-1
3. 利用cfd與服務器端進行數據通信。