1. 程式人生 > >嵌入式Linux網路程式設計

嵌入式Linux網路程式設計


             TCP:Transmission Control Protocol 傳輸控制協議TCP是一種面向連線(連線導向)的、可靠的、基於位元組流的運輸層(Transport layer)通訊協議。

OSI 協議參考模型,它是基於國際標準化組織(ISO)的建議發展起來的,從上到下共分為7 層:應用層、表示層、會話層、傳輸層、網路層、資料鏈路層及物理層

TCP/IP 參考模型  :從上到下共分為4 層  :應用層、傳輸層、網路層、網路介面層

TCP:為應用程式提供可靠的通訊連線。適合於一次傳輸大批資料的情況。並適用於要求得到響應的應用程式。
UDP:提供了無連線通訊,且不對傳送包進行可靠的保證。適合於一次傳輸少量資料,可靠性則由應用層來負責。

TCP 三次握手協議
TCP對話通過三次握手來初始化的。三次握手的目的是使資料段的傳送和接收同步,告訴其他主機其一次可接收的資料量,並建立虛連線。

三次握手的簡單過程。
· 初始化主機通過一個同步標誌置位的資料段發出會話請求。
· 接收主機通過發回具有以下專案的資料段表示回覆:同步標誌置位、即將傳送的資料段的起始位元組的順序號、應答並帶有將收到的下一個資料段的位元組順序號。
· 請求主機再回送一個數據段,並帶有確認順序號和確認號。

UDP

UDP 即使用者資料報協議,它是一種無連線協議,因此不需要像TCP 那樣通過三次握手來建立一個連線。同時,一個UDP應用可同時作為應用的客戶或伺服器方。由於UDP協議
並不需要建立一個明確的連線,因此建立UDP應用要比建立TCP應用簡單得多。

socket

socket介面是一種特殊的I/O,它也是一種檔案描述符。每一個socket都用一個半相關描述{協議,本地地址、本地埠}來表示;一個完整的套接字則用一個相關描述{協議,本地地址、本地埠、遠端地址、遠端埠}

socket有3 種類型
(1)流式socket(SOCK_STREAM)
流式套接字提供可靠的、面向連線的通訊流;它使用TCP協議,從而保證了資料傳輸的正確性和順序性。
(2)資料報socket(SOCK_DGRAM)
資料報套接字定義了一種無連線的服務,資料通過相互獨立的報文進行傳輸,是無序的,並且不保證是可靠、無差錯的。它使用資料報協議UDP。
(3)原始socket
原始套接字允許對底層協議如IP或ICMP進行直接訪問,它功能強大但使用較為不便,主要用於一些協議的開發。

地址結構相關處理

   1 . 下面首先介紹兩個重要的資料型別:sockaddr 和sockaddr_in,這兩個結構型別都是用來儲存socket資訊的,如下所示:

[cpp] view plaincopyprint?
  1. struct sockaddr {  
  2. unsigned short sa_family; /*地址族*/
  3. char sa_data[14]; /*14位元組的協議地址,包含該socket的IP地址和埠號。*/
  4. };  
  5. struct sockaddr_in {  
  6. shortint sa_family; /*地址族*/
  7. unsigned shortint sin_port; /*埠號*/
  8. struct in_addr sin_addr; /*IP地址*/
  9. unsigned char sin_zero[8]; /*填充0 以保持與struct sockaddr同樣大小*/
  10. };  
struct sockaddr {
unsigned short sa_family; /*地址族*/
char sa_data[14]; /*14位元組的協議地址,包含該socket的IP地址和埠號。*/
};
struct sockaddr_in {
short int sa_family; /*地址族*/
unsigned short int sin_port; /*埠號*/
struct in_addr sin_addr; /*IP地址*/
unsigned char sin_zero[8]; /*填充0 以保持與struct sockaddr同樣大小*/
};

    這兩個資料型別是等效的,可以相互轉化,通常sockaddr_in資料型別使用更為方便。在建立socketadd或sockaddr_in後,就可以對該socket 進行適當的操作了。

  2.結構欄位

     下面列出了該結構sa_family欄位可選的常見值。

結構定義標頭檔案#include <netinet/in.h>
AF_INET:IPv4協議
AF_INET6:IPv6協議
AF_LOCAL:UNIX域協議
AF_LINK:鏈路地址協議
Sa_family
AF_KEY:金鑰套接字(socket)

htons、ntohs、htonl、ntohl。這四個地址分別實現網路位元組序和主機位元組序的轉化,這裡的h 代表host,n 代表network,s 代表short,l 代表long

3.地址格式轉化函式

          在IPv4 中用到的函式有inet_aton、inet_addr 和inet_ntoa,而IPv4 和IPv6 相容的函式有inet_pton 和inet_ntop。在IPv4 中用到的函式有inet_aton、inet_addr 和inet_ntoa,而IPv4 和IPv6 相容的函式有inet_pton 和inet_ntop。

      inet_pton 函式是將點分十進位制地址對映為二進位制地址,而inet_ntop 是將二進位制地址對映為點分十進位制地址。

     函式原型如下:

         int inet_pton(int family,const char *strptr, void *addrptr)  strptr:要轉化的值   addrptr:轉化後的地址

         int inet_ntop(int family, void *addrptr, char *strptr, size_t len)     addrptr:轉化後的地址  strptr:要轉化的值 

4.名字地址轉化

               一些函式可以實現主機名和地址的轉化,最為常見的有gethostbyname、gethostbyaddr、getaddrinfo等

              gethostbyname 是將主機名轉化為IP 地址,gethostbyaddr 則是逆操作,是將IP地址轉化為主機名,另外getaddrinfo還能實現自動識別IPv4地址和IPv6地址。

            gethostbyname和gethostbyaddr 都涉及到一個hostent 的結構體

[cpp] view plaincopyprint?
  1. Struct hostent{  
  2. char *h_name;/*正式主機名*/
  3. char **h_aliases;/*主機別名*/
  4. int h_addrtype;/*地址型別*/
  5. int h_length;/*地址長度*/
  6. char **h_addr_list;/*指向IPv4或IPv6的地址指標陣列*/
  7. }  
Struct hostent{
char *h_name;/*正式主機名*/
char **h_aliases;/*主機別名*/
int h_addrtype;/*地址型別*/
int h_length;/*地址長度*/
char **h_addr_list;/*指向IPv4或IPv6的地址指標陣列*/
}

      呼叫該函式後就能返回hostent 結構體的相關資訊。
     

[cpp] view plaincopyprint?
  1. struct addrinfo{  
  2. int ai_flags;/*AI_PASSIVE,AI_CANONNAME;*/
  3. int ai_family;/*地址族*/
  4. int ai_socktype;/*socket型別*/
  5. int ai_protocol;/*協議型別*/
  6. size_t ai_addrlen;/*地址長度*/
  7. char *ai_canoname;/*主機名*/
  8. struct sockaddr *ai_addr;/*socket結構體*/
  9. struct addrinfo *ai_next;/*下一個指標連結串列*/
  10. }  
struct addrinfo{
int ai_flags;/*AI_PASSIVE,AI_CANONNAME;*/
int ai_family;/*地址族*/
int ai_socktype;/*socket型別*/
int ai_protocol;/*協議型別*/
size_t ai_addrlen;/*地址長度*/
char *ai_canoname;/*主機名*/
struct sockaddr *ai_addr;/*socket結構體*/
struct addrinfo *ai_next;/*下一個指標連結串列*/
}


    getaddrinfo函式涉及到一個addrinfo的結構體

標頭檔案:           #include <netdb.h>
函式原型

           Struct hostent *gethostbyname(const char *hostname)      Hostname:主機名

            Int getaddrinfo(const char *hostname,const char *service,const struct addrinfo*hints,struct addrinfo **result)    service:服務名或十進位制的串列埠號字串   hints:服務線索   result:返回結果

 -----------    socket基礎程式設計

socket程式設計的基本函式有socket、bind、listen、accept、send、sendto、recv、recvfrom這幾個

· socket:該函式用於建立一個socket連線,可指定socket型別等資訊。在建立了socket連線之後,可對socketadd或sockaddr_in進行初始化,以儲存所建立的socket資訊。
· bind:該函式是用於將本地IP 地址繫結埠號的,若繫結其他地址則不能成功。另外,它主要用於TCP的連線,而在UDP的連線中則無必要。
· connect:該函式在TCP中是用於bind的之後的client 端,用於與伺服器端建立連線,而在UDP中由於沒有了bind函式,因此用connect有點類似bind函式的作用。
· send和recv:這兩個函式用於接收和傳送資料,可以用在TCP中,也可以用在UDP中。當用在UDP時,可以在connect函式建立連線之後再用。
· sendto和recvfrom:這兩個函式的作用與send和recv函式型別,也可以用在TCP和UDP中。當用在TCP時,後面的幾個與地址有關引數不起作用,函式作用等同於send和recv;當用在UDP時,可以用在之前沒有使用connect的情況時,這兩個函式可以自動尋找制定地址並進行連線。

用TCP協議socket程式設計流程圖

用UDP協議socket程式設計流程圖

函式格式

所需標頭檔案#include <sys/socket.h>
函式原型int socket(int family, int type, int protocol)    

          family:協議族  type:套接字型別:SOCK_STREAM:位元組流套接字socket   SOCK_DGRAM:資料報套接字socket  SOCK_RAW:原始套接字socket

函式原型int bind(int sockfd,struct sockaddr *my_addr, int addrlen)    socktd:套接字描述符 my_addr:本地地址  addrlen:地址長度

函式原型int listen(int sockfd, int backlog)    Backlog:請求佇列中允許的最大請求數,大多數系統預設值為20

函式原型int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)    addr:客戶端地址  addrlen:地址長度

函式原型int connect(int sockfd, struct sockaddr *serv_addr, int addrlen)  serv_addr:伺服器端地址  addrlen:地址長度

函式原型int send(int sockfd, const void *msg, int len, int flags)  msg:指向要傳送資料的指標  len:資料長度   flags:一般為0

函式原型int recv(int sockfd,void *buf,int len,unsigned int flags)

函式原型int sendto(int sockfd, const void *msg,int len,unsigned int flags,const struct sockaddr*to, int tolen)

函式原型int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *from,int*fromlen)  from:源機的IP地址和埠號資訊  tolen:地址長度

一個簡單的C/S例子

server.c

[cpp] view plaincopyprint?
  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <errno.h>
  6. #include <string.h>
  7. #include <unistd.h>
  8. #include <netinet/in.h>
  9. #define SERVPORT 3333
  10. #define BACKLOG 10
  11. #define MAX_CONNECTED_NO 10
  12. #define MAXDATASIZE 5
  13. int main()  
  14. {  
  15. struct sockaddr_in server_sockaddr,client_sockaddr;  
  16. int sin_size,recvbytes;  
  17. int sockfd,client_fd;  
  18. char buf[MAXDATASIZE];  
  19. /*建立socket連線*/
  20. if((sockfd = socket(AF_INET,SOCK_STREAM,0))== -1){  
  21. perror("socket");  
  22. exit(1);  
  23. }  
  24. printf("socket success!,sockfd=%d\n",sockfd);  
  25. /*設定sockaddr_in 結構體中相關引數*/
  26. server_sockaddr.sin_family=AF_INET;  
  27. server_sockaddr.sin_port=htons(SERVPORT);  
  28. server_sockaddr.sin_addr.s_addr=INADDR_ANY;  
  29. bzero(&(server_sockaddr.sin_zero),8);  
  30. /*繫結函式bind*/
  31. if(bind(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(struct
  32. sockaddr))== -1){  
  33. perror("bind");  
  34. exit(1);  
  35. }  
  36. printf("bind success!\n");  
  37. /*呼叫listen函式*/
  38. if(listen(sockfd,BACKLOG)== -1){  
  39. perror("listen");  
  40. exit(1);  
  41. }  
  42. printf("listening....\n");  
  43. /*呼叫accept函式,等待客戶端的連線*/
  44. if((client_fd=accept(sockfd,(struct sockaddr *)&client_sockaddr,&sin_  
  45. size))== -1){  
  46. perror("accept");  
  47. exit(1);  
  48. }  
  49. /*呼叫recv函式接收客戶端的請求*/
  50. if((recvbytes=recv(client_fd,buf,MAXDATASIZE,0))== -1){  
  51. perror("recv");  
  52. exit(1);  
  53. }  
  54. printf("received a connection :%s\n",buf);  
  55. close(sockfd);  
  56. }  
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#define SERVPORT 3333
#define BACKLOG 10
#define MAX_CONNECTED_NO 10
#define MAXDATASIZE 5
int main()
{
struct sockaddr_in server_sockaddr,client_sockaddr;
int sin_size,recvbytes;
int sockfd,client_fd;
char buf[MAXDATASIZE];
/*建立socket連線*/
if((sockfd = socket(AF_INET,SOCK_STREAM,0))== -1){
perror("socket");
exit(1);
}
printf("socket success!,sockfd=%d\n",sockfd);
/*設定sockaddr_in 結構體中相關引數*/
server_sockaddr.sin_family=AF_INET;
server_sockaddr.sin_port=htons(SERVPORT);
server_sockaddr.sin_addr.s_addr=INADDR_ANY;
bzero(&(server_sockaddr.sin_zero),8);
/*繫結函式bind*/
if(bind(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(struct
sockaddr))== -1){
perror("bind");
exit(1);
}
printf("bind success!\n");
/*呼叫listen函式*/
if(listen(sockfd,BACKLOG)== -1){
perror("listen");
exit(1);
}
printf("listening....\n");
/*呼叫accept函式,等待客戶端的連線*/
if((client_fd=accept(sockfd,(struct sockaddr *)&client_sockaddr,&sin_
size))== -1){
perror("accept");
exit(1);
}
/*呼叫recv函式接收客戶端的請求*/
if((recvbytes=recv(client_fd,buf,MAXDATASIZE,0))== -1){
perror("recv");
exit(1);
}
printf("received a connection :%s\n",buf);
close(sockfd);
}

client.c

[cpp] view plaincopyprint?
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <errno.h>
  4. #include <string.h>
  5. #include <netdb.h>
  6. #include <sys/types.h>
  7. #include <netinet/in.h>
  8. #include <sys/socket.h>
  9. #define SERVPORT 3333
  10. #define MAXDATASIZE 100
  11. main(int argc,char *argv[]){  
  12. int sockfd,sendbytes;  
  13. char buf[MAXDATASIZE];  
  14. struct hostent *host;  
  15. struct sockaddr_in serv_addr;  
  16. if(argc < 2){  
  17. fprintf(stderr,"Please enter the server's hostname!\n");  
  18. exit(1);  
  19. }  
  20. /*地址解析函式*/
  21. if((host=gethostbyname(argv[1]))==NULL){  
  22. perror("gethostbyname");  
  23. exit(1);  
  24. }  
  25. /*建立socket*/
  26. if((sockfd=socket(AF_INET,SOCK_STREAM,0))== -1){  
  27. perror("socket");  
  28. exit(1);  
  29. }  
  30. /*設定sockaddr_in 結構體中相關引數*/
  31. serv_addr.sin_family=AF_INET;  
  32. serv_addr.sin_port=htons(SERVPORT);  
  33. serv_addr.sin_addr=*((struct in_addr *)host->h_addr);  
  34. bzero(&(serv_addr.sin_zero),8);  
  35. /*呼叫connect函式主動發起對伺服器端的連線*/
  36. if(connect(sockfd,(struct sockaddr *)&serv_addr,\  
  37. sizeof(struct sockaddr))== -1){  
  38. perror("connect");  
  39. exit(1);  
  40. }  
  41. /*傳送訊息給伺服器端*/
  42. if((sendbytes=send(sockfd,"hello",5,0))== -1){  
  43. perror("send");  
  44. exit(1);  
  45. }  
  46. close(sockfd);  
  47. }  
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define SERVPORT 3333
#define MAXDATASIZE 100
main(int argc,char *argv[]){
int sockfd,sendbytes;
char buf[MAXDATASIZE];
struct hostent *host;
struct sockaddr_in serv_addr;
if(argc < 2){
fprintf(stderr,"Please enter the server's hostname!\n");
exit(1);
}
/*地址解析函式*/
if((host=gethostbyname(argv[1]))==NULL){
perror("gethostbyname");
exit(1);
}
/*建立socket*/
if((sockfd=socket(AF_INET,SOCK_STREAM,0))== -1){
perror("socket");
exit(1);
}
/*設定sockaddr_in 結構體中相關引數*/
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(SERVPORT);
serv_addr.sin_addr=*((struct in_addr *)host->h_addr);
bzero(&(serv_addr.sin_zero),8);
/*呼叫connect函式主動發起對伺服器端的連線*/
if(connect(sockfd,(struct sockaddr *)&serv_addr,\
sizeof(struct sockaddr))== -1){
perror("connect");
exit(1);
}
/*傳送訊息給伺服器端*/
if((sendbytes=send(sockfd,"hello",5,0))== -1){
perror("send");
exit(1);
}
close(sockfd);
}




網路高階程式設計網路高階程式設計所需標頭檔案   #include <sys/socket.h>
函式原型int socket(int family, int type, int protocol)所需標頭檔案#include <sys/socket.h>
函式原型int socket(int family, int type, int protocol)所需標頭檔案#include <sys/socket.h>
函式原型int socket(int family, int type, int protocol)呼叫該函式後就能返回hostent 結構體的相關資訊。
getaddrinfo函式涉及到一個addrinfo的結構體呼叫該函式後就能返回hostent 結構體的相關資訊。
getaddrinfo函式涉及到一個addrinfo的結構體

5.網路高階程式設計

    之前介紹的如connet、recv、send都是阻塞性函式,若資源沒有準備好,則呼叫該函式的程序將進入睡眠狀態,這樣就無法處理I/O 多路複用的情況了,fcntl和select是了兩種解決I/O 多路複用的解決方法

1.fcntl
函式fcntl針對socket程式設計提供瞭如下的程式設計特性。
· 非阻塞I/O:可將cmd設定為F_SETFL,將lock設定為O_NONBLOCK。
· 訊號驅動I/O:可將cmd設定為F_SETFL,將lock設定為O_ASYNC。

簡單的例子fcntl.c

[cpp] view plaincopyprint?
  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <sys/wait.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <errno.h>
  7. #include <string.h>
  8. #include <sys/un.h>
  9. #include <sys/time.h>
  10. #include <sys/ioctl.h>
  11. #include <unistd.h>
  12. #include <netinet/in.h>
  13. #include <fcntl.h>
  14. #define SERVPORT 3333
  15. #define BACKLOG 10
  16. #define MAX_CONNECTED_NO 10
  17. #define MAXDATASIZE 100
  18. int main()  
  19. {  
  20. struct sockaddr_in server_sockaddr,client_sockaddr;  
  21. int sin_size,recvbytes,flags;  
  22. int sockfd,client_fd;  
  23. char buf[MAXDATASIZE];  
  24. if((sockfd = socket(AF_INET,SOCK_STREAM,0))== -1){  
  25. perror("socket");  
  26. exit(1);  
  27. }  
  28. printf("socket success!,sockfd=%d\n",sockfd);  
  29. server_sockaddr.sin_family=AF_INET;  
  30. server_sockaddr.sin_port=htons(SERVPORT);  
  31. server_sockaddr.sin_addr.s_addr=INADDR_ANY;  
  32. bzero(&(server_sockaddr.sin_zero),8);  
  33. if(bind(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(struct
  34. sockaddr))== -1){  
  35. perror("bind");  
  36. exit(1);  
  37. }  
  38. printf("bind success!\n");  
  39. if(listen(sockfd,BACKLOG)== -1){  
  40. perror("listen");  
  41. exit(1);  
  42. }  
  43. printf("listening....\n");  
  44. /*呼叫fcntl函式設定非阻塞引數*/
  45. if((flags=fcntl( sockfd, F_SETFL, 0))<0)  
  46. perror("fcntl F_SETFL");  
  47. flag |= O_NONBLOCK;  
  48. if(fcntl(fd,F_SETEL,flags)<0)  
  49. perror("fcntl");  
  50. while(1){  
  51. sin_size=sizeof(struct sockaddr_in);  
  52. if((client_fd=accept(sockfd,(structsockaddr*)&client_sockaddr,  
  53. &sin_size))== -1){  
  54. perror("accept");  
  55. exit(1);  
  56. }  
  57. if((recvbytes=recv(client_fd,buf,MAXDATASIZE,0))== -1){  
  58. perror("recv");  
  59. exit(1);  
  60. }  
  61. if(read(client_fd,buf,MAXDATASIZE)<0){  
  62. perror("read");  
  63. exit(1);  
  64. }  
  65. printf("received a connection :%s",buf);  
  66. close(client_fd);  
  67. exit(1);  
  68. }/*while*/
  69. }  
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/un.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <netinet/in.h>
#include <fcntl.h>
#define SERVPORT 3333
#define BACKLOG 10
#define MAX_CONNECTED_NO 10
#define MAXDATASIZE 100
int main()
{
struct sockaddr_in server_sockaddr,client_sockaddr;
int sin_size,recvbytes,flags;
int sockfd,client_fd;
char buf[MAXDATASIZE];
if((sockfd = socket(AF_INET,SOCK_STREAM,0))== -1){
perror("socket");
exit(1);
}
printf("socket success!,sockfd=%d\n",sockfd);
server_sockaddr.sin_family=AF_INET;
server_sockaddr.sin_port=htons(SERVPORT);
server_sockaddr.sin_addr.s_addr=INADDR_ANY;
bzero(&(server_sockaddr.sin_zero),8);
if(bind(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(struct
sockaddr))== -1){
perror("bind");
exit(1);
}
printf("bind success!\n");
if(listen(sockfd,BACKLOG)== -1){
perror("listen");
exit(1);
}
printf("listening....\n");
/*呼叫fcntl函式設定非阻塞引數*/
if((flags=fcntl( sockfd, F_SETFL, 0))<0)
perror("fcntl F_SETFL");
flag |= O_NONBLOCK;
if(fcntl(fd,F_SETEL,flags)<0)
perror("fcntl");
while(1){
sin_size=sizeof(struct sockaddr_in);
if((client_fd=accept(sockfd,(structsockaddr*)&client_sockaddr,
&sin_size))== -1){
perror("accept");
exit(1);
}
if((recvbytes=recv(client_fd,buf,MAXDATASIZE,0))== -1){
perror("recv");
exit(1);
}
if(read(client_fd,buf,MAXDATASIZE)<0){
perror("read");
exit(1);
}
printf("received a connection :%s",buf);
close(client_fd);
exit(1);
}/*while*/
}

2.select
使用fcntl 函式雖然可以實現非阻塞I/O 或訊號驅動I/O,但在實際使用時往往會對資源是否準備完畢進行迴圈測試,這樣就大大增加了不必要的CPU 資源。select函式還可以設定等待的時

select_socket.c

[cpp] view plaincopyprint?
  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <sys/wait.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <errno.h>
  7. #include <string.h>
  8. #include <sys/un.h>
  9. #include <sys/time.h>
  10. #include <sys/ioctl.h>
  11. #include <unistd.h>
  12. #include <netinet/in.h>
  13. #define SERVPORT 3333
  14. #define BACKLOG 10
  15. #define MAX_CONNECTED_NO 10
  16. #define MAXDATASIZE 100
  17. int main()  
  18. {  
  19. struct sockaddr_in server_sockaddr,client_sockaddr;  
  20. int sin_size,recvbytes;  
  21. fd_set readfd;  
  22. fd_set writefd;  
  23. int sockfd,client_fd;  
  24. char buf[MAXDATASIZE];  
  25. if((sockfd = socket(AF_INET,SOCK_STREAM,0))== -1){  
  26. perror("socket");  
  27. exit(1);  
  28. }  
  29. printf("socket success!,sockfd=%d\n",sockfd);  
  30. server_sockaddr.sin_family=AF_INET;  
  31. server_sockaddr.sin_port=htons(SERVPORT);  
  32. server_sockaddr.sin_addr.s_addr=INADDR_ANY;  
  33. bzero(&(server_sockaddr.sin_zero),8);  
  34. if(bind(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(struct
  35. sockaddr))== -1){  
  36. perror("bind");  
  37. exit(1);  
  38. }  
  39. printf("bind success!\n");  
  40. if(listen(sockfd,BACKLOG)== -1){  
  41. perror("listen");  
  42. exit(1);  
  43. }  
  44. printf("listening....\n");  
  45. /*將呼叫socket函式的描述符作為檔案描述符*/
  46. FD_ZERO(&readfd);  
  47. FD_SET(sockfd,&readfd);  
  48. while(1){  
  49. sin_size=sizeof(struct sockaddr_in);  
  50. /*呼叫select函式*/
  51. if(select(MAX_CONNECTED_NO,&readfd,NULL,NULL,(struct timeval *)0)>0){  
  52. if(FD_ISSET(sockfd,&readfd)>0){  
  53. if((client_fd=accept(sockfd,(struct sockaddr *)&client_  
  54. sockaddr,&sin_size))== -1){  
  55. perror("accept");  
  56. exit(1);  
  57. }  
  58. if((recvbytes=recv(client_fd,buf,MAXDATASIZE,0))== -1){  
  59. perror("recv");  
  60. exit(1);  
  61. }  
  62. if(read(client_fd,buf,MAXDATASIZE)<0){  
  63. perror("read");  
  64. exit(1);  
  65. }  
  66. printf("received a connection :%s",buf);  
  67. }/*if*/
  68. close(client_fd);  
  69. }/*select*/
  70. }/*while*/
  71. }  
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/un.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <netinet/in.h>
#define SERVPORT 3333
#define BACKLOG 10
#define MAX_CONNECTED_NO 10
#define MAXDATASIZE 100
int main()
{
struct sockaddr_in server_sockaddr,client_sockaddr;
int sin_size,recvbytes;
fd_set readfd;
fd_set writefd;
int sockfd,client_fd;
char buf[MAXDATASIZE];
if((sockfd = socket(AF_INET,SOCK_STREAM,0))== -1){
perror("socket");
exit(1);
}
printf("socket success!,sockfd=%d\n",sockfd);
server_sockaddr.sin_family=AF_INET;
server_sockaddr.sin_port=htons(SERVPORT);
server_sockaddr.sin_addr.s_addr=INADDR_ANY;
bzero(&(server_sockaddr.sin_zero),8);
if(bind(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(struct
sockaddr))== -1){
perror("bind");
exit(1);
}
printf("bind success!\n");
if(listen(sockfd,BACKLOG)== -1){
perror("listen");
exit(1);
}
printf("listening....\n");
/*將呼叫socket函式的描述符作為檔案描述符*/
FD_ZERO(&readfd);
FD_SET(sockfd,&readfd);
while(1){
sin_size=sizeof(struct sockaddr_in);
/*呼叫select函式*/
if(select(MAX_CONNECTED_NO,&readfd,NULL,NULL,(struct timeval *)0)>0){
if(FD_ISSET(sockfd,&readfd)>0){
if((client_fd=accept(sockfd,(struct sockaddr *)&client_
sockaddr,&sin_size))== -1){
perror("accept");
exit(1);
}
if((recvbytes=recv(client_fd,buf,MAXDATASIZE,0))== -1){
perror("recv");
exit(1);
}
if(read(client_fd,buf,MAXDATASIZE)<0){
perror("read");
exit(1);
}
printf("received a connection :%s",buf);
}/*if*/
close(client_fd);
}/*select*/
}/*while*/
}

下面是實現簡單的linux 下的TCP通訊程式

伺服器端的程式碼如下:

server.c

[cpp] view plaincopyprint?
  1. <P>#include<stdio.h>  
  2. #include<stdlib.h>
  3. #include<errno.h>
  4. #include<string.h>
  5. #include<sys/types.h>
  6. #include<netinet/in.h>
  7. #include<sys/socket.h>
  8. #include<sys/wait.h>
  9. #include<pthread.h></P><P>#define MYPORT 3490
  10. #define BACKLOG 10 
  11. #define MAXDATASIZE 1024</P><P>int sockfd,new_fd;
  12. pthread_t  accthread,recthread;</P><P>void recmessage(void){  
  13. while(1){  
  14. int numbytes;  
  15. char buf[MAXDATASIZE];  
  16. if((numbytes = recv(new_fd,buf,MAXDATASIZE,0)) == -1){  
  17. perror("recv");  
  18.    exit(1);  
  19.      }  
  20.       buf[numbytes] = '\0';  
  21. if(strcmp(buf,"exit") == 0){  
  22.  printf("Client is closed\n");  
  23.  close(new_fd);  
  24.  close(sockfd);  
  25.  exit(1);  
  26. }  
  27.  printf("Client:%s\n",buf);  
  28.   }  
  29. }</P><P>  
  30. void acceptconnect(void){  
  31. struct sockaddr_in their_addr;  
  32. int sin_size;  
  33.  sin_size = sizeof(struct sockaddr_in);  
  34. if((new_fd = accept(sockfd,(struct sockaddr*)&their_addr,&sin_size)) == -1){  
  35.     perror("accept");  
  36.     exit(1);  
  37.    }  
  38.   printf("server:got connection from %s\n",inet_ntoa(their_addr.sin_addr));  
  39. if((pthread_create(&recthread,NULL,(void *)recmessage,NULL))!= 0){  
  40.     printf("Create thread error!\r\n");  
  41.     exit(1);  
  42.   }  
  43. }  
  44. int main(void){  
  45. struct sockaddr_in my_addr;  
  46. if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1){  
  47.    perror("socket");  
  48.    exit(1);  
  49.   }  
  50.   my_addr.sin_family = AF_INET;  
  51.   my_addr.sin_port = htons(MYPORT);  
  52.   my_addr.sin_addr.s_addr = INADDR_ANY;  
  53.   bzero(&(my_addr.sin_zero),8);  
  54. if(bind(sockfd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr)) == -1){  
  55.    perror("bind");  
  56.    exit(1);  
  57.    }  
  58. if(listen(sockfd,BACKLOG) == -1){  
  59.     perror("listen");  
  60.     exit(1);  
  61.    }  
  62. if((pthread_create(&accthread,NULL,(void *)acceptconnect,NULL)) != 0){  
  63.     printf("Create thread error!\r\n");  
  64.     exit(1);  
  65.    }  
  66. while(1){  
  67. char msg[MAXDATASIZE];  
  68.   scanf("%s",msg);  
  69. if(send(new_fd,msg,strlen(msg),0) == -1){  
  70.    perror("send");  
  71.    close(new_fd);  
  72.    exit(1);  
  73.   }  
  74. if(strcmp(msg,"exit") == 0){  
  75.    printf("Byebye!\n");  
  76.    close(new_fd);  
  77.    close(sockfd);  
  78.    exit(1);  
  79.   }  
  80.  }  
  81. return 0;  
  82. }  
  83. </P>  

#include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<sys/types.h> #include<netinet/in.h> #include<sys/socket.h> #include<sys/wait.h> #include<pthread.h>

#define MYPORT 3490 #define BACKLOG 10 #define MAXDATASIZE 1024

int sockfd,new_fd; pthread_t  accthread,recthread;

void recmessage(void){     while(1){       int numbytes;       char buf[MAXDATASIZE];       if((numbytes = recv(new_fd,buf,MAXDATASIZE,0)) == -1){ perror("recv");    exit(1);      }       buf[numbytes] = '\0';   if(strcmp(buf,"exit") == 0){  printf("Client is closed\n");  close(new_fd);  close(sockfd);  exit(1); }  printf("Client:%s\n",buf);   } }

void acceptconnect(void){  struct sockaddr_in their_addr;  int sin_size;  sin_size = sizeof(struct sockaddr_in);  if((new_fd = accept(sockfd,(struct sockaddr*)&their_addr,&sin_size)) == -1){     perror("accept");     exit(1);    }   printf("server:got connection from %s\n",inet_ntoa(their_addr.sin_addr));    if((pthread_create(&recthread,NULL,(void *)recmessage,NULL))!= 0){     printf("Create thread error!\r\n");     exit(1);   } } int main(void){  struct sockaddr_in my_addr;  if((sockfd = socket(AF_INET,S