服务器端:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PORT 5678
#define MAX 10//需要监视的最大的文件描述符值+1为10
int main()
{
int sockfd,newsockfd,fd,is_connected[MAX];
struct sockaddr_in addr;
int addr_len=sizeof(struct sockaddr_in);
fd_set myreadfds;
char msgbuffer[256];
char msg[]="This is the message from server.Connected,\n"; //对新连接的套接字的欢迎语
//建立套接字
if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)
{
perror("socket");
exit(1);
}
else
{
printf("socket created .\n");
printf("socket id:%d \n",sockfd);
}
//设置socket状态,允许在bind函数中本地地址可重复使用。
int on=1;
if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(int))<0)
{
perror("setsockopt");
exit(1);
}
//添加套接字的信息,下面信息代表服务器会在端口5678和服务器所拥有的所有网卡(ip)上监听接收信息
bzero(&addr,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY);
addr.sin_port=htons(PORT);
//绑定端口信息到新建立的socket上面
if (bind(sockfd,(struct sockaddr*)&addr,sizeof(addr))<0)
{
perror("connect");
exit(1);
}
else
{
printf("connected .\n");
printf("local port : %d\n",PORT);
}
//服务器开始进行监听。3表示该进程可以入队等待的连接请求数量.
if(listen(sockfd,3)<0)
{
perror("listen");
exit(1);
}
else
{
printf("listening......\n");
}
//把is_connected[fd]重置为零
for(fd=0;fd0;//置零
}
while(1)
{
FD_ZERO(&myreadfds);//清空套接字集
FD_SET(sockfd,&myreadfds);//新加入的文件描述符,即新建的套接字,把第sockfd位置一
for(fd=0;fdif(is_connected[fd])
{
FD_SET(fd,&myreadfds);
}
}//判断并加载上次返回的情况
if(!select(MAX,&myreadfds,NULL,NULL,NULL))//select会更新这个集合,把其中不可读的套接字去掉
{
continue;
}
for(fd=0;fdif(FD_ISSET(fd,&myreadfds))//检查fd是否在这个集合里面
{
if(sockfd==fd)//检查侦听套接字和fd是否相同
{
if ((newsockfd=accept(sockfd,(struct sockaddr*)(&addr),&addr_len))<0)//建立通信套接字
{
perror("accept");
exit(1);
}
else
{
printf("accepted\n");
}
write(newsockfd,msg,sizeof(msg)); //发送欢迎语is_connected[newsockfd]=1;//将通信套接字的位置置一
printf("connect from%s\n",inet_ntoa(addr.sin_addr));
}
else{
//对可读**通信套接字**的操作
bzero(msgbuffer,sizeof(msgbuffer)); //清零
if(read(fd,msgbuffer,sizeof(msgbuffer))<=0)
{
printf("connect closed.\n");
is_connected[fd]=0;//不可读就从集合中删除
close(fd);
}
else
{
write(fd,msgbuffer,sizeof(msgbuffer));//发送已经接收到的东西
printf("message:%s \n",msgbuffer);
} } } } }}
客户端:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PORT 5678
#define REMOTEIP "127.0.0.1"
#define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE);} while(0) //定义出错函数
int main(int argc,char *argv[])
{
int s;
int addr_len=sizeof(struct sockaddr_in);
char mybuffer[256];
//建立套接字
if((s=socket(AF_INET,SOCK_STREAM,0))<0)
{
ERR_EXIT("socket");
}
else
{
printf("socket created .\n");
printf("socket id:%d \n",s);
}
struct sockaddr_in addr;
bzero(&addr,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=inet_addr(REMOTEIP);
addr.sin_port=htons(PORT);
//请求建立连接
if(connect(s,(struct sockaddr*)&addr,addr_len)<0)
{
ERR_EXIT("connect");
}
else
{
printf("connected ok!\n");
printf("remote ip:%s\n",REMOTEIP);
printf("remote port:%d\n",PORT);
}
//接收并输出欢迎语
recv(s,mybuffer,sizeof(mybuffer),0);
printf("%s\n",mybuffer);
while(1)
{
bzero(mybuffer,sizeof(mybuffer));
read(STDIN_FILENO,mybuffer,sizeof(mybuffer));//从键盘中读取输入的数据mybuffer
if(write(s,mybuffer,sizeof(mybuffer))<=0)
{//将mybuffer写入套接字
ERR_EXIT("send");
}
else
{
bzero(mybuffer,sizeof(mybuffer));
read(s,mybuffer,sizeof(mybuffer));
printf("recieved:%s\n",mybuffer);
}
}
}
运行结果
客户端:
服务器端:
对select函数的详解:
select()函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET
关于对出错函数定义使用方面有兴趣的可以参考这篇博文,讲的非常详细
#define+do{} while(0)+peeror的思考