Message.h
#ifndef _MESSAGE_H_
#define _MESSAGE_H_
#include<string.h>
#include<stdlib.h>
typedef struct loing
{
int fid;
char username[20];
struct loing* next;
} loing;
loing * Init()
{
loing* head =(loing*)malloc(sizeof(loing));
head->next = NULL;
return head;
}
int Selectname(loing* head, char* name)
{
loing* p1 = head->next;
int ret = 0;
while(p1!=NULL)
{
if(strcmp(name,p1->username)==0)
{
ret = p1->fid;
break;
}
p1=p1->next;
}
return ret;
}
int Inset(loing* head,int id,char *name)
{
int ret = 0;
if((ret=Selectname(head,name))>0)
{
return ret;
}
else{
loing *p2 = (loing*)malloc(sizeof(loing));
p2->fid = id;
strcpy(p2->username,name);
p2->next = NULL;
p2->next = head->next;
head->next = p2;
return ret;
}
}
int Deletename(loing* head, char* name)
{
loing* p1 = head->next;
loing* p2 = head;
int ret = 0;
while(p1!=NULL)
{
if(strcmp(name,p1->username)==0)
{
ret =p1->fid;
p2->next = p1->next;
free(p1);
break;
}
p2 = p2->next;
p1=p1->next;
}
return ret;
}
typedef struct Mesg
{
int id;
char username[20];
char destname[20];
char message[1024];
}Mesg;
#endif
wrap.h
#ifndef __WRAP_H__
#define __WRAP_H__
void sys_err_exit(const char*s );
int Accept(int fd ,struct sockaddr *sa ,socklen_t *salenptr);
void Bind(int fd,const struct sockaddr *sa,socklen_t salen);
void Connect(int fd,const struct sockaddr *sa,socklen_t salen);
void Listen(int fd,int backlog);
int Socket(int family,int type,int protocol);
ssize_t Write(int fd,const void *ptr,size_t nbytes);
void Close(int fd);
ssize_t Read(int fd,void* ptr,size_t nbytes);
ssize_t Readn(int fd,void *vptr,size_t n);
ssize_t Writen(int fd,const void *ptr,size_t nbytes);
static ssize_t my_read(int fd,char *ptr);
ssize_t ReadLine(int fd,void* vptr,size_t maxlen);
#endif
wrap.c
#include<unistd.h>
#include<errno.h>
#include<stdlib.h>
#include<sys/socket.h>
void sys_err_exit(const char* str)
{
perror(str);
exit(1);
}
//对accept函数的从新封装
int Accept(int fd,struct sockaddr *sa,socklen_t *salenptr)
{
int n;
again:
if((n = accept(fd,sa,salenptr))<0)
{
if((errno == ECONNABORTED) || (errno == EINTR))
//如果是网络重链接错误,或者时信号打断则从新接受链接
goto again;
else
sys_err_exit("accept error");
}
return n;
}
//对bind函数的封装
void Bind(int fd, struct sockaddr* sa,socklen_t salen)
{
if(bind(fd,sa,salen)<0)
sys_err_exit("bind error");
}
//对connect函数的封装
void Connect(int fd,const struct sockaddr *sa,socklen_t salen)
{
if(connect(fd,sa,salen) < 0)
sys_err_exit("connect error");
}
//对listen函数的封装
void Listen(int fd,int backlog)
{
if(listen(fd,backlog) < 0)
sys_err_exit("listen error");
}
//对socket函数的封装
int Socket(int family,int type,int protocol)
{
int n;
if((n = socket(family,type,protocol)) < 0)
sys_err_exit("socket error");
return n;
}
//对read函数的封装
ssize_t Read(int fd,void *ptr,size_t nbytes)
{
ssize_t n;
again:
if((n = read(fd,ptr,nbytes)) == -1)
{
if(errno == EINTR)
//如果时被信号打断从新去读
goto again;
else
return -1;
}
return n;
}
//对write函数的封装
ssize_t Write(int fd,const void *ptr,size_t nbytes)
{
ssize_t n;
again:
if((n=write(fd,ptr,nbytes))==-1)
{
if(errno == EINTR)
goto again;
else
return -1;
}
return n;
}
//对close函数的封装
void Close(int fd)
{
if(close(fd)==-1)
sys_err_exit("close error");
}
//对读n个字节的封装
ssize_t Readn(int fd,void *vptr,size_t n)
{
size_t nleft;//剩余的字节
ssize_t nread; //已经读的字节
char *ptr;
ptr = vptr;
nleft = n;
while(nleft > 0)
{
if((nread = read(fd, ptr, nleft))<0)
{
if(errno == EINTR)
//如果时被信号打断已经读的清除
nread = 0;
else
return -1;
}
else if(nread == 0)//另一端已经关闭
break;
nleft -= nread;//计算还剩余多少字节没有读
ptr += nread;//指针后移到已经读的字节,以便下次从此处继续保存
}
return n-nleft;//返回实际读到的字节数
}
//对读n个字节的封装
ssize_t Writen(int fd,const void *vptr,size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr;
ptr = vptr;
nleft = n;
while(nleft > 0)
{
if((nwritten = write(fd,ptr,nleft)) < 0)
{
if(nwritten < 0 && errno == EINTR)
nwritten = 0;
else
return -1;
}
nleft -= nwritten;
ptr += nwritten;
}
return n;
}
//预读取函数
static ssize_t my_read(int fd,char *ptr)
{
static int read_cnt;
static char *read_ptr;
static char read_buf[100];
if(read_cnt <= 0)
{
again:
if((read_cnt = read(fd,read_buf,sizeof(read_buf)))<0)
{
if(errno == EINTR)
goto again;
return -1;
}
else if(read_cnt == 0)
return 0;
read_ptr = read_buf;
}
read_cnt-- ;
*ptr = *read_ptr++;
return 1;
}
//读一行函数封装
ssize_t ReadLine(int fd,void *vptr,size_t maxlen)
{
ssize_t n,rc;
char c,*ptr;
ptr = vptr;
for(n=1;n < maxlen;n++)
{
if((rc = my_read(fd,&c)) ==1 )
{
*ptr++ = c;
if(c == '\n')
break;
}
else if(rc == 0)
{
*ptr = 0;
return n-1;
}
else
{
return -1;
}
}
*ptr = 0;
return n;
}
Serve.c
#include<signal.h>
#include<pthread.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<fcntl.h>
#include<stdlib.h>
#include<Message.h>
#include <sys/types.h>
#include <sys/stat.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include"wrap.h"
#define SERVE_PORT 8000
struct s_info
{
struct sockaddr_in cliaddr;
int connfd;
};
loing* head=NULL;
void sys_err(char *str)
{
perror(str);
exit(1);
}
pthread_mutex_t conter_mutex = PTHREAD_MUTEX_INITIALIZER;
void dong(int i)
{
while(waitpid(0,NULL,WNOHANG)>0)
;
}
void *do_work(void *arg)
{
Mesg mes;
struct s_info *ts = (struct s_info*)arg;
int cilenfd = ts->connfd;
char str[INET_ADDRSTRLEN];
printf("Mssage from IP %s at PORT %d \n ",inet_ntop(AF_INET,&(*ts).cliaddr.sin_addr,str,sizeof(str)),ntohs((*ts).cliaddr.sin_port));
pthread_detach(pthread_self());
while(1)
{
int n = 0;
//从公共管道中读取数据
n = read(cilenfd,&mes,sizeof(mes));
if(n>0)
{ //如果id是1则代表登录
if(mes.id == 1)
{
// if(head == NULL)
// printf("head is NULL\n");
//登录时打开私有管道,并把pid写如链表
// pthread_mutex_lock(&conter_mutex);
int cilenfd1= Inset(head,cilenfd,mes.username);
// pthread_mutex_unlock(&conter_mutex);
// printf("%s,%d,%d\n",mes.username,cilenfd1,cilenfd);
if(cilenfd1>0)//此处说明此用户已经登录过
{
strcpy(mes.username,mes.username);
char mms[]="请不要重复登录";
strcpy(mes.message,mms);
mes.id=-1;
write(cilenfd1,&mes,sizeof(mes));
}
else
{
strcpy(mes.username,mes.username);
char bbf[]="登录成功";
strcpy(mes.message,bbf);
write(cilenfd,&mes,sizeof(mes));
}
}
if(mes.id == 2)
{
if(strcmp(mes.username,mes.destname)==0)
continue;
int cilenfd1 = Selectname(head,mes.destname);
// printf("%s , %d\n",mes.destname,cilenfd1);
if(cilenfd1 == 0)
{
cilenfd1 = Selectname(head,mes.username);
char mms[50];
strcpy(mms,mes.destname);
char mm[] = " :没有在线,请稍等片刻";
strcat(mms,mm);
strcpy(mes.username,mes.username);
strcpy(mes.message,mms);
write(cilenfd1,&mes,sizeof(mes));
}
else
write(cilenfd1,&mes,sizeof(mes));
}
if(mes.id == 0)
{
int cilenfd1 = Deletename(head,mes.username);
char tui[] ="退出成功!";
strcpy(mes.username,mes.username);
strcpy(mes.message,tui);
mes.id = -1;
write(cilenfd1,&mes,sizeof(mes));
}
}
}
Close(ts->connfd);
// return (void*)0;
}
int main(void)
{
head = Init();
int servefd,cilenfd;
char buf[1024];
struct sockaddr_in serve,clien;
char str[INET_ADDRSTRLEN];
socklen_t cilen_len;
//signal(SIGPIPE,dong);
struct s_info ts[300];
int t = 0;
pthread_t tid;
servefd = Socket(AF_INET,SOCK_STREAM,0);
bzero(&serve,sizeof(serve));
serve.sin_family = AF_INET;
serve.sin_port = htons(SERVE_PORT);
serve.sin_addr.s_addr = htonl(INADDR_ANY);
int pot = 1;
setsockopt(servefd,SOL_SOCKET,SO_REUSEADDR,&pot,sizeof(pot));
Bind(servefd,(struct sockaddr*)&serve,sizeof(serve));
Listen(servefd,20);
printf("Accepting connections .....\n");
while(1)
{
cilen_len = sizeof(clien);
cilenfd = Accept(servefd,(struct sockaddr*)&clien,&cilen_len);
ts[t].cliaddr = clien;
ts[t].connfd = cilenfd;
if(t>=300)
{
printf("cilen is too much\n");
return 0;
}
pthread_create(&tid,NULL,do_work,(void*)&ts[t]);
t++;
// printf("t=%d\n",t);
}
return 0;
}
Clent.c
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<fcntl.h>
#include<stdlib.h>
#include<Message.h>
#include <sys/types.h>
#include <sys/stat.h>
#include<netinet/in.h>
#include"wrap.h"
#define SERVE_PORT 8000
#define SERVE_IP "192.168.42.27"
#define SERVE_FIFO "serve_public"
void sys_err(char *str)
{
perror(str);
exit(1);
}
int main(int argc,char* argv[])
{
int plic_id,pive_id,read_id;
struct sockaddr_in servaddr;
int sockfd;
int fbg;
char buf[1024];
Mesg loin,mes;
if(argc<2)//判断输入格式是否正确
{
printf("%s\n","please input like:./clent username");
return 0;
}
/* //打包登录数据包
loin.id=1;
strcpy(loin.username,argv[1]);
*/
sockfd = Socket(AF_INET,SOCK_STREAM,0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERVE_PORT);
inet_pton(AF_INET,SERVE_IP,&servaddr.sin_addr.s_addr);
Connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr));
int flags;
flags = fcntl(STDIN_FILENO,F_GETFL);
flags |=O_NONBLOCK;
if(fcntl(STDIN_FILENO,F_SETFL,flags) == -1)
sys_err("fcntl stdin error");
int flags1;
flags1 = fcntl(sockfd,F_GETFL);
flags1 |=O_NONBLOCK;
if(fcntl(sockfd,F_SETFL,flags) == -1)
sys_err("fcntl stdin error");
//从公共管道传送到服务器,进行登录
// write(sockfd,&loin,sizeof(loin));
char tui[]="T~";
char de[]="D~";
while(1)
{
strcpy(mes.username,argv[1]);
int n =0;
n = read(STDIN_FILENO,buf,1024);
if(n > 0)
{
mes.id = 2;
buf[n]='\0';
strcpy(mes.destname,strtok(buf," "));
strcpy(mes.message,strtok(NULL," "));
if((strncmp(mes.message,tui,2)==0))
mes.id = 0;
if((strncmp(mes.message,de,2)==0))
mes.id = 1;
write(sockfd,&mes,sizeof(mes));
}
int n1 =0;
n1 = read(sockfd,&mes,sizeof(mes));
if(n1>0)
{
printf("%s",mes.username);
printf(":\n");
printf("%s\n",mes.message);
fflush(stdout);
if(mes.id==-1)
{
exit(1);
}
}
}
return 0;
}
网络编程QQ实现
最新推荐文章于 2021-05-28 21:32:55 发布