1. 套接字数据通信中使用标准IO函数:
a. 具有良好的移植性portability; //所有标准函数都具有良好的移植性
b. 标准IO可以利用缓冲提高性能;
2. 使用标准IO的几个缺陷
a. 不容易进行双向通信; //同时读写方式打开r+,w+,a+
b. 有时候可能频繁调用fflush; //每次切换读写都应该调用fflush
c. 需要以FILE结构体指针形式返回文件描述符; //需要文件描述符转成FILE的方法
3. fdopen将文件描述符转换成FILE结构体指针
#include <stdio.h>
FILE * fdopen(int fildes, const char *mode);
成功返回转换的FILE结构体指针,失败NULL
fildes :需要转换的文件描述符
mode:将要创建的FILE结构体指针的mode信息 //与fopen的打开模式相同
#include <stdio.h>
int fileno(FILE * stream);
成功返回转换后的文件描述符,失败-1
5. 使用标准IO实现echo服务器/客户端
server:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 1024
void error_handling(char *message);
int main(int argc, char *argv[]){
int serv_sock,clnt_sock;
char message[BUF_SIZE];
int str_len,i;
struct sockaddr_in serv_adr;
struct sockaddr_in clnt_adr;
socklen_t clnt_adr_sz;
FILE * readfp;
FILE * writefp;
if(argc != 2){
printf("Usage : %s <port>\n",argv[0]);
exit(1);
}
serv_sock = socket(PF_INET,SOCK_STREAM,0);
if(serv_sock == -1){
error_handling("socket() error");
}
memset(&serv_adr,0,sizeof(serv_adr));
serv_adr.sin_family=AF_INET;
serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);
serv_adr.sin_port=htons(atoi(argv[1]));
if(bind(serv_sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr)) == -1){
error_handling("bind() error");
}
if(listen(serv_sock,5) == -1){
error_handling("listen error");
}
clnt_adr_sz = sizeof(clnt_adr);
for(i=0;i<5;i++){
clnt_sock = accept(serv_sock,(struct sockaddr*)&clnt_adr,&clnt_adr_sz);
if(clnt_sock == -1){
error_handling("accept error");
}else{
printf("connected client %d %d\n",i+1,clnt_sock);
}
readfp = fdopen(clnt_sock,"r");
writefp = fdopen(clnt_sock,"w");
while(!feof(readfp)){
fgets(message,BUF_SIZE,readfp);
fputs(message,writefp);
fflush(writefp);
}
printf("disconnected client %d \n",clnt_sock);
fclose(readfp);
fclose(writefp);
}
close(serv_sock);
return 0;
}
void error_handling(char *message){
fputs(message,stderr);
fputs("\n",stderr);
exit(1);
}
执行结果:
alex@alex-virtual-machine:/extra/tcpip/15$ ./server 9190
connected client 1 4
disconnected client 4
connected client 2 4
disconnected client 4
client:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 1024
void error_handling(char *message);
int main(int argc, char *argv[]){
int sock;
char message[BUF_SIZE];
int str_len;
struct sockaddr_in serv_adr;
FILE * readfp;
FILE * writefp;
if(argc != 3){
printf("Usage : %s <IP> <port>\n",argv[0]);
exit(1);
}
sock = socket(PF_INET,SOCK_STREAM,0);
if(sock == -1){
error_handling("socket() error");
}
memset(&serv_adr,0,sizeof(serv_adr));
serv_adr.sin_family=AF_INET;
serv_adr.sin_addr.s_addr=inet_addr(argv[1]);
serv_adr.sin_port=htons(atoi(argv[2]));
if(connect(sock,(struct sockaddr *)&serv_adr,sizeof(serv_adr)) == -1){
error_handling("connect error");
}else {
puts("connected...");
}
readfp = fdopen(sock,"r");
writefp = fdopen(sock,"w");
while(1){
fputs("Insert message(q to quit):",stdout);
fgets(message,BUF_SIZE,stdin);
if(!strcmp(message,"q\n") || !strcmp(message,"Q\n"))
break;
fputs(message,writefp);
fflush(writefp);
fgets(message,BUF_SIZE,readfp);
printf("Message from server: %s",message);
}
fclose(writefp);
fclose(readfp);
return 0;
}
void error_handling(char *message){
fputs(message,stderr);
fputs("\n",stderr);
exit(1);
}
执行结果:
alex@alex-virtual-machine:/extra/tcpip/15$ ./client 127.0.0.1 9190
connected...
Insert message(q to quit):hello
Message from server: hello
Insert message(q to quit):q
alex@alex-virtual-machine:/extra/tcpip/15$ ./client 127.0.0.1 9190
connected...
Insert message(q to quit):what
Message from server: what
Insert message(q to quit):q
alex@alex-virtual-machine:/extra/tcpip/15$