嵌入式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資訊的,如下所示:
- struct sockaddr {
- unsigned short sa_family; /*地址族*/
- char sa_data[14]; /*14位元組的協議地址,包含該socket的IP地址和埠號。*/
- };
- struct sockaddr_in {
- shortint sa_family; /*地址族*/
- unsigned shortint sin_port; /*埠號*/
- struct in_addr sin_addr; /*IP地址*/
- unsigned char sin_zero[8]; /*填充0 以保持與struct sockaddr同樣大小*/
- };
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?- Struct hostent{
- char *h_name;/*正式主機名*/
- char **h_aliases;/*主機別名*/
- int h_addrtype;/*地址型別*/
- int h_length;/*地址長度*/
- char **h_addr_list;/*指向IPv4或IPv6的地址指標陣列*/
- }
Struct hostent{
char *h_name;/*正式主機名*/
char **h_aliases;/*主機別名*/
int h_addrtype;/*地址型別*/
int h_length;/*地址長度*/
char **h_addr_list;/*指向IPv4或IPv6的地址指標陣列*/
}
呼叫該函式後就能返回hostent 結構體的相關資訊。
- 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;/*下一個指標連結串列*/
- }
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?- #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);
- }
#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?- #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 <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?- #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*/
- }
#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?- #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*/
- }
#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?- <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></P><P>#define MYPORT 3490
- #define BACKLOG 10
- #define MAXDATASIZE 1024</P><P>int sockfd,new_fd;
- pthread_t accthread,recthread;</P><P>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);
- }
- }</P><P>
- 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,SOCK_STREAM,0)) == -1){
- perror("socket");
- exit(1);
- }
- my_addr.sin_family = AF_INET;
- my_addr.sin_port = htons(MYPORT);
- my_addr.sin_addr.s_addr = INADDR_ANY;
- bzero(&(my_addr.sin_zero),8);
- if(bind(sockfd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr)) == -1){
- perror("bind");
- exit(1);
- }
- if(listen(sockfd,BACKLOG) == -1){
- perror("listen");
- exit(1);
- }
- if((pthread_create(&accthread,NULL,(void *)acceptconnect,NULL)) != 0){
- printf("Create thread error!\r\n");
- exit(1);
- }
- while(1){
- char msg[MAXDATASIZE];
- scanf("%s",msg);
- if(send(new_fd,msg,strlen(msg),0) == -1){
- perror("send");
- close(new_fd);
- exit(1);
- }
- if(strcmp(msg,"exit") == 0){
- printf("Byebye!\n");
- close(new_fd);
- close(sockfd);
- exit(1);
- }
- }
- return 0;
- }
- </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