1、網絡通訊簡介html
NAME socket - create an endpoint for communication //功能: 用來建立一個終端的連接 SYNOPSIS #include <sys/types.h> #include <sys/socket.h> int socket(int domain, //這個參數用來選擇網絡協議族, int type, //用來指定套接類型, int protocol); //這個參數通常指定爲0 除非用於建立原始協議族時才設置爲其餘值
#include <sys/socket.h> int socketfd ; socketfd=socket(PF_INET,SOCK_STREAM,0); if(-1 == socketfd) { perror("service"); return socketfd; }
NAME bind - bind a name to a socket //爲套接字指定名稱 SYNOPSIS #include <sys/types.h> #include <sys/socket.h> int bind( int sockfd, //套接字文件描述符 const struct sockaddr *my_addr, //通用的套接字地址指針 socklen_t addrlen); //第二個參數佔用的字節數 sizeof(my_addr) DESCRIPTION bind() gives the socket sockfd the local address my_addr. my_addr is addrlen bytes long. Traditionally, this is called 「assigning a name to a socket.」 When a socket is created with socket(2), it exists in a name space (address family) but has no name assigned.
/* * 1003.1g requires sa_family_t and that sa_data is char. */ struct sockaddr { sa_family_t sa_family; /* address family, AF_xxx */ char sa_data[14]; /* 14 bytes of protocol address */ };
struct sockaddr_in { sa_family_t sin_family; /* Address family */ //socket 網絡協議族類型 __be16 sin_port; /* Port number */ //要綁定的本地端口號 struct in_addr sin_addr; /* Internet address*/ //本機的IP地址 /* Pad to size of `struct sockaddr'. */ unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) - sizeof(unsigned short int) - sizeof(struct in_addr)]; // 第四個域一般不用賦值 };
struct in_addr 的定義以下: /* Internet address. */ struct in_addr { __be32 s_addr; };
NAME inet_aton, inet_addr, inet_network, inet_ntoa, inet_makeaddr, inet_lnaof, inet_netof - Internet address manipulation routines SYNOPSIS #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int inet_aton(const char *cp, struct in_addr *inp); in_addr_t inet_addr(const char *cp); //將字符串"192.168.0.12"轉換爲32bit的IP地址 in_addr_t inet_network(const char *cp); char *inet_ntoa(struct in_addr in); //將32bit的IP地址轉換爲 "192.168.0.12"字符串 struct in_addr inet_makeaddr(int net, int host); in_addr_t inet_lnaof(struct in_addr in); in_addr_t inet_netof(struct in_addr in);
#include <sys/socket.h> #include <netinet/in.h> struct sockaddr_in bind_addr; socklen_t addr_len; //綁定本地端口,即爲socketfd命名 bind_addr.sin_family = AF_INET; bind_addr.sin_port= htons (6000); //通信端口,服務器端和客戶機端必須同樣 bind_addr.sin_addr.s_addr= inet_addr("192.168.0.101"); //本機的IP地址 addr_len=sizeof(struct sockaddr_in); ret = bind(socketfd,(struct sockaddr*)&bindaddr, addr_len); if(-1==ret) { perror("bind"); return ret; }
LISTEN(2) Linux Programmer’s Manual LISTEN(2) NAME listen - listen for connections on a socket SYNOPSIS #include <sys/socket.h> int listen(int sockfd, //要監聽的網絡套接字文件描述符 int backlog); //能夠服務的最大客戶端數目,或者說監聽隊列的長度
#include <sys/socket.h> socketfd = listen(socketfd, 10);
ACCEPT(2) Linux Programmer’s Manual ACCEPT(2) NAME accept - accept a connection on a socket SYNOPSIS #include <sys/types.h> #include <sys/socket.h> int accept( int sockfd, //要監聽的網絡套接字文件的描述符 struct sockaddr *addr, //輸出參數,用來存放接收到的客戶機的網絡地址信息 socklen_t *addrlen); //輸出參數,用來存放客戶機的網絡地址信息的長度
#include <sys/socket.h> struct sockaddr_in client_addr; socklen_t client_addr_len; //響應監聽隊列的請求,並建立緩存數據文件 client_addr_len = sizeof(struct sockaddr_in); sockbuf_fd=accept(socketfd,(struct sockaddr*)&client_addr, &client_addr_len); if(-1 == sockbuf_fd) { perror("accept"); return sockbuf_fd; }
Exp: //發送數據 ret=write(sock_buf_fd,"socket network serives test.\n",29); if(-1 == ret) { perror("send data"); return ret; } //接收數據 memset(sock_buf,0,sizeof(sockbuf)); ret=read(sock_buf_fd,sock_buf,sizeof(sock_buf)); if(-1 == ret) { perror("read socket"); return ret; }
close(sock_buf_fd);
close(socket_fd);
int socket_fd; socket_fd = socket( PF_INET, SOCK_STREAM, 0 );
CONNECT(2) Linux Programmer’s Manual CONNECT(2) NAME connect - initiate a connection on a socket SYNOPSIS #include <sys/types.h> #include <sys/socket.h> int connect( int sockfd, //創建的套接字文件 const struct sockaddr *serv_addr, //指定要鏈接到服務的地址信息結構體的指針 socklen_t addrlen); //參數2 的長度
#include <sys/socket.h> #include <netinet/in.h> int ret; struct sockaddr_in srv_addr; srv_addr.sin_family =AF_INET; srv_addr.sin_port= htons(6000); srv_addr.sin_addr.s_addr= inet_addr("192.168.0.101"); ret =connect(socket_fd , (struct sockaddr*)&srv_addr , sizeof(struct sockaddr_in) )
memset(buf, 0 , sizeof(buf) ); //將緩衝區域清空的緣由是定義的buf裏面存在一些其餘數據,若是不清空,數據將錯誤 ret=read(socket_fd,buf,sizeof(buf)); if(ret<0) { perror("read"); return ret; } ret=write(socket_fd,buf,strlen(buf)); //若是在讀以前不清空 buf ,那麼這個地方 strlen(buf) 就要改成 ret ; if(ret<0) { perror("write"); return ret; }
//本文件用來測試網絡通訊 #include <stdio.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <string.h> int main(int argc,char* argv[]) { int socket_fd; int ret; struct sockaddr_in bind_addr; struct sockaddr_in client_addr; socklen_t addr_len; int sock_buf_fd; char sock_buf[1024]; //建立網絡套接字 socket_fd=socket(PF_INET,SOCK_STREAM,0); if(-1 == socket_fd) { perror("service"); return socket_fd; } //綁定本地端口,即爲socket_fd命名 bind_addr.sin_family = PF_INET; bind_addr.sin_port= htons (6000); bind_addr.sin_addr.s_addr= inet_addr("192.168.0.101"); addr_len=sizeof(struct sockaddr_in); ret = bind(socket_fd,(struct sockaddr*)&bind_addr, addr_len); //監聽端口 ret=listen(socket_fd, 10); if(-1 == ret) { perror("listen"); return ret; } //響應監聽隊列的請求,並建立緩存數據文件 sock_buf_fd=accept(socket_fd,(struct sockaddr*)&client_addr,&addr_len); if(-1 == sock_buf_fd) { perror("accept"); return sock_buf_fd; } //發送數據 ret=write(sock_buf_fd,"socket network serives test.\n",29); if(-1 == ret) { perror("send data"); return ret; } //接收數據 memset(sock_buf,0,sizeof(sock_buf)); ret=read(sock_buf_fd,sock_buf,sizeof(sock_buf)); if(-1 == ret) { perror("read socket"); return ret; } printf("%s\n",sock_buf); close(sock_buf_fd); close(socket_fd); return 0; }
client.c 看成客戶程序linux
//本文件用來測試linux網絡編程 #include <stdio.h> #include <sys/socket.h> #include <unistd.h> #include <netinet/in.h> #include <string.h> int main(int argc,char*argv[]) { int ret; int socket_fd; struct sockaddr_in srv_addr; socklen_t addr_len; char buf[1024]; //建立網絡套接字文件 socket_fd=socket(PF_INET,SOCK_STREAM,0); if(-1 == socket_fd ) { perror("socket"); return socket_fd; } //申請創建與服務器的鏈接 srv_addr.sin_family=PF_INET; srv_addr.sin_port=htons(6000); srv_addr.sin_addr.s_addr = inet_addr("192.168.0.101"); //服務器IP地址 addr_len=sizeof(struct sockaddr_in); ret=connect(socket_fd,(struct sockaddr *)&srv_addr, addr_len); if(-1==ret) { perror("connect"); return -1; } memset(buf,0,sizeof(buf)); ret=read(socket_fd,buf,sizeof(buf)); if(ret<0) { perror("read"); return ret; } ret=write(socket_fd,buf,strlen(buf)); if(ret<0) { perror("write"); return ret; } close(socket_fd); return 0; }
[root@localhost tcpip]# ./service //在服務器端運行 service 程序,執行後再等待客戶程序請求服務 socket network serives test. //在客戶端執行 ./client 後 打印出這個信息 [root@localhost tcpip]#
/ # ./client
/ #
//本文件是用於簡單文件傳輸程序的頭文件 #if !defined(__FTP_H__) #define __FTP_H__ #define TEL_LEN 512 //報文數據長度爲512字節 #define FILE_EXIST 0x0 #define FILE_NOT_EXIST 0x1 #define END_OF_FILE 0x2 #define VALID_DATA 0x3 typedef struct tel_gram { unsigned char type; char data[TEL_LEN]; }tel_t; typedef struct pthread_type { struct sockaddr_in *sock_in_addr; int sock_buf_fd ; }pthread_type_t; #endif
//本文件用來實現一個簡單的文件傳輸服務 #include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <unistd.h> #include <pthread.h> #include "ftp.h" #include <fcntl.h> int transfer(pthread_type_t *arg) { int fd; int ret; int size; int sock_buf_fd; char file_name[512]; tel_t telgram; struct sockaddr_in* cli_addr; //輸出客戶機信息 cli_addr=arg->sock_in_addr; printf("the connet client is %s .\n",inet_ntoa(cli_addr->sin_addr.s_addr) ); #if 0 //首先檢測連接是否正常 sock_buf_fd=arg->sock_buf_fd; ret=recv( sock_buf_fd, //接收數據的socket數據緩衝文件 &telgram, //存粗接收數據的緩衝去地址 sizeof(tlegram.type), //要接收的數據長度 0); //接收標誌 if(ret != sizeof(tlegram.type)) { printf("network establelish is not well. will exit\n"); return 1; } send(sock_buf_fd,&telgram,sizeof(tlegram.type),0); #endif //接受文件名 sock_buf_fd=arg->sock_buf_fd; ret=recv(sock_buf_fd, file_name,512,0); if(-1==ret) { perror("recv file name"); return 1; } //切換到默認路徑,默認文件存放路徑爲/ftp目錄 chdir("/ftp"); if( access(file_name, F_OK) ) { telgram.type=FILE_NOT_EXIST; //若是文件不存在就發送信息給客戶端 send(sock_buf_fd,&telgram,sizeof(telgram.type),0); return 1; } //打開要傳送的文件 fd=open(file_name,O_RDONLY); if(-1==fd) { return -1; } while(1) { telgram.type=VALID_DATA; ret=read(fd, &telgram.data,TEL_LEN); size=sizeof(telgram); if(ret<TEL_LEN) { telgram.type=END_OF_FILE; size =ret + sizeof(telgram.type); } send(sock_buf_fd,&telgram, size,0); } return 0; } int main(int argc,char* argv[]) { int sock_fd; int sock_buf_fd; int ret; struct sockaddr_in srv_addr; //服務器IP地址、端口信息 struct sockaddr_in cli_addr; //用來存儲客戶段地址信息 socklen_t srv_addr_len; //保存服務器IP地址、端口信息的結構體數據長度 socklen_t cli_addr_len; //保存客戶機IP地址、端口信息的結構體數據長度 pthread_type_t pth_arg; //創建網絡套接字文件 sock_fd=socket(PF_INET, //使用TCP/IP協議族 SOCK_STREAM, //使用字符流,TCP協議,須要創建穩定連接 0); //非創建原始協議,必須傳 0 if(-1 == sock_fd ) { perror("create socket"); return sock_fd; } //綁定本地端口,即爲套接字接口命名 srv_addr.sin_family=PF_INET; //指定綁定的協議 srv_addr.sin_port=htons(6000); //指定通訊端口 srv_addr.sin_addr.s_addr=inet_addr("192.168.0.101"); //指定服務起的IP srv_addr_len=sizeof(struct sockaddr_in); ret=bind( sock_fd, //要綁定的套接字文件 (struct sockaddr *)&srv_addr, //服務器網絡信息結構體 srv_addr_len); //第二個參數的sizeof if(-1 == ret) { perror("socket bind"); return ret; } //監聽端口 ret=listen(sock_fd, //要監聽的套解字,即要監聽的端口 5); //最大監聽隊列 if(-1 == ret) { perror("socket liseten"); return ret; } //查看請求,並創建數據緩存文件 while(1) { sock_buf_fd=accept( sock_fd, //輸入參數 (struct sockaddr*)&cli_addr, //輸出參數 客戶機IP &cli_addr_len); //第二個參數的sizeof pth_arg.sock_buf_fd=sock_buf_fd; //數據緩存文件指針傳遞給線程 pth_arg.sock_in_addr=&cli_addr; ret=transfer(&pth_arg); if(ret) { break ; } } close(sock_buf_fd); close(sock_fd); return 0; }
//本文件實現簡單文件傳輸軟件的客戶端 #include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include "ftp.h" int main(int argc,char* argv[]) { int fd; int ret; int sock_fd; struct sockaddr_in srv_addr; tel_t telgram; int size; //檢測程序執行時的參數是否正確 //不正確輸出提示信息 if(argc<2 || argc > 3) { printf("Usage: client filename\n"); return 0; } //打開網絡套接字文件 sock_fd=socket( PF_INET, //與服器程序同樣 SOCK_STREAM, 0 ); if(-1 == sock_fd) { perror("socket"); return 0; } //申請與服務器創建鏈接 srv_addr.sin_family=PF_INET; srv_addr.sin_port=htons(6000); srv_addr.sin_addr.s_addr=inet_addr("192.168.0.101"); ret=connect(sock_fd,(struct sockaddr*)&srv_addr, sizeof(srv_addr)); if(-1 == ret) { perror("connet to server"); return 0; } //發送文件名給服務器 send(sock_fd,argv[1],strlen(argv[1]),0); recv(sock_fd,&telgram,sizeof(telgram.type),0); if(FILE_NOT_EXIST == telgram.type) { printf("Not such a file in servie mathcine,will quit transfer\n"); return 0; } //建立文件來接受數據 fd=open(argv[1], O_WRONLY | O_CREAT | O_TRUNC); if(-1 == fd ) { perror("create file"); return 0; } while(1) { size=recv(sock_fd, &telgram, sizeof(telgram), 0); if(END_OF_FILE == telgram.type) { ret=write(fd,&telgram.data,size); if(ret<size) { //若是寫入的數據比讀到的數據少,表示寫入錯誤刪除文件 unlink(argv[1]); perror("local file write"); } break; } ret=write(fd, &telgram.data, size); if(ret<size) { //若是寫入的數據比讀到的數據少,表示寫入錯誤刪除文件 unlink(argv[1]); perror("local file write"); break ; } } close(fd); close(sock_fd); return 0; }
【linux草鞋應用編程系列】_5_網絡編程編程
本系列文章歡迎批評指正,歡迎指正錯誤。緩存
本系列文章,未完待續.........服務器