客户端
利用select实现
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <strings.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#define SERV_PORT 5001 //5000~65535
#define SERV_IP_ADDR "192.168.1.94" //local ip
int main()
{
int fd=-1;//定义fd备用
struct sockaddr_in sin;//定义填充结构体备用,强转为sockaddr使用
/*1 create socket fd*/
if((fd=socket(AF_INET,SOCK_STREAM,0))<0){//申请文件描述符
perror ("socket");
exit(-1);
}
/*2.connect with sever net*/
bzero(&sin,sizeof(sin));//清零结构体 并给结构体变量赋值
sin.sin_family=AF_INET;
sin.sin_port = htons(SERV_PORT);
sin.sin_addr.s_addr=inet_addr(SERV_IP_ADDR);
connect(fd,(struct sockaddr *)&sin,sizeof(sin));//在套接字上启动连接
/*3 .read write*/
fd_set rset;//定义一个rset集合用来存放文件描述符
int maxfd = -1;//定义最大容量
int ret=-1;
struct timeval tout;//定义超时结构体
char buf[BUFSIZ];
while(1) {
FD_ZERO(&rset);//清0
FD_SET(0,&rset);//将标准输入0的文件描述符存入
FD_SET(fd,&rset);//将网络套接字socket的文件描述符fd存入
maxfd=fd;//将此时的fd记为最大文件描述符
tout.tv_sec=5;//超时结构体秒赋值
tout.tv_usec=0;//超时结构体毫秒赋值
select(maxfd+1,&rset,NULL,NULL,&tout);// 当调用select()时,由内核根据IO状态修改fd_set的内容,
//由此来通知执 行了select()的进程哪一Socket或文件可读或可写。主要用于Socket通信当中!
if(FD_ISSET(0,&rset)) { //标准键盘.上有输入
//读取键盘输入,发送到网络套接字fd
bzero(buf,BUFSIZ);
do {
ret=read(0,buf,BUFSIZ-1);//读取
} while(ret<0&&EINTR == errno);
if(ret < 0) {
perror("read"); //读取失败 继续
continue;
}
if (!ret)
continue; //读取为空
if (write(fd,buf,strlen(buf)) <0) {// 将在标准输入读取到的内容 发送(写入)给网络套接字
perror("write() to socket");
continue;
}
if (!strncasecmp (buf,"quit",4)) { //用户输入了 quit字符
printf("Client is exiting!\n");
break; //接受到quit 退出
}
}
if(FD_ISSET(fd,&rset)){//服务 器给发送过来了数据
//读取套接字数据,处理
bzero(buf,BUFSIZ);
do{
ret = read(fd,buf,BUFSIZ-1);//读取网络套接字发送过来的内容
}while(ret < 0 && EINTR == errno);
if(ret < 0){
perror("read from socket");
continue;
}
if(!ret) break; /*服务器关闭*/
//There is a BUG, FIXME! !
printf("S:---------->%s\n",buf); //将接受的网络套接字的内容由标准输出 输出
if (!strncasecmp (buf,"quit",4)) { //用户输入了 quit字符
printf("Sender Client is exiting!\n");
break;
}
}
}
/*4 close fd*/
close(fd); //关闭网络套接字
return 0;
}
服务器
这里为了使服务器代码简单,把函数检错移了出来,专门利用一个net.c实现,继而又写了个net.h
net.h
#ifndef __NET_H__
#define __NET_H__
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <strings.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#define SERV_PORT 5001
int ssocket(int domain, int type, int protocol);
int bbind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
int llisten(int sockfd, int backlog);
int aaccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int cconnect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
#endif
net.c
#include "net.h"
int ssocket(int domain, int type, int protocol)
{
int sret;
sret =socket(domain,type,protocol);
if(sret<0)
perror("socket");
else
return sret;
}
int bbind(int sockfd, const struct sockaddr *addr,socklen_t addrlen)
{
int bret;
bret=bind(sockfd,addr,addrlen);
if(bret<0)
perror("bind");
else
return 0;
}
int llisten(int sockfd, int backlog)
{
int lret;
lret=listen(sockfd,backlog);
if(lret<0)
perror("bind");
else
return 0;
}
int aaccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
{
int aret;
again:
aret=accept(sockfd,addr,addrlen);
if (aret < 0) {
if ((errno == ECONNABORTED)||(errno == EINTR))
goto again;
else
perror("accept");
}
return aret;
}
int cconnect(int sockfd, const struct sockaddr *addr,socklen_t addrlen)
{
int cret;
connect(sockfd,addr,addrlen);
if(cret<0)
perror("connect");
else
return 0;
}
最后就是服务器了
server.c
使用了两个线程,分别对应收发
#include "net.h"
#include <strings.h>
#define SRV_PORT 5001
void *do_work(void *arg);
void *do_works(void *arg);
struct s_info{
struct sockaddr_in cliaddr;
int connfd;
};
int main()
{
int lfd,cfd;
pthread_t tid,fid;
struct sockaddr_in srv_addr,clt_addr;
socklen_t clt_addr_len;
clt_addr_len = sizeof(clt_addr);
srv_addr.sin_family = AF_INET;
srv_addr.sin_port = htons(SRV_PORT);
srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
lfd=ssocket(AF_INET,SOCK_STREAM,0);
int b_reuse=1;
setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&b_reuse,sizeof(int));
bbind(lfd,(struct sockaddr *)&srv_addr,sizeof(srv_addr));
llisten(lfd,128);
struct s_info ts[256];
int i=0;
while(1)
{
cfd=aaccept(lfd,(struct sockaddr *)&clt_addr,&clt_addr_len);
ts[i].cliaddr = clt_addr;
ts[i].connfd = cfd;
//printf(" 新设备连接ip=%s 线程=%d\n", ntohl(ts[i].cliaddr.sin_addr.s_addr), ts[i].connfd);
printf(" 新设备线程=%d\n", ts[i].connfd);
pthread_create(&tid,NULL,do_work,(void* )&ts[i]);
pthread_create(&fid,NULL,do_works,(void* )&ts[i]);
pthread_detach(tid);
pthread_detach(fid);
i++;
}
return 0;
}
void *do_work(void *arg)
{
int n,i;
struct s_info *ts=(struct s_info *)arg;
char buf[BUFSIZ];
// char str[16]="已收到\n";
while(1)
{
n =read(ts->connfd,buf,BUFSIZ-1);
if(n==0)
{
printf("exit______\n");
exit(1);
}
// write(1,buf,n);
printf("C:---------->%s\n",buf);
bzero(&buf,sizeof(buf));
}
close(ts->connfd);
return (void *)0;
}
void *do_works(void *arg)
{
struct s_info *ts=(struct s_info *)arg;
char strr[BUFSIZ];
while(1)
{
read(0,strr,BUFSIZ-1);
write(ts->connfd,strr,BUFSIZ-1);
bzero(&strr,sizeof(strr));
}
close(ts->connfd);
return (void *)0;
}
版权声明:本文为weixin_44532706原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。