- 建立socket:
建立一个适用于ipv4协议的流式套接字
int sockfd;
if((sockfd = socket(PF_INET,SOCK_STREAM,0))<0)
{
perror("socket error\n");
exit(0);
}
- 服务器端套接字与本地地址相连:
struct sockaddr_in addr;
addr.sin_family = PF_INET;
addr.sin_port = htons(S_PORT);
addr.sin_addr.s_addr = inet_addr(S_IP);
if(bind(sockfd,(struct sockaddr *)&addr,sizeof(addr)) < 0)
{
perror("bind error\n");
exit(1);
}
- 服务器端监听请求队列
设置队列大小为conn_size
if (listen(sockfd,conn_size) < 0)
{
perror("listen error\n");
exit(1);
}
- 客户端将套接字与远程主机连接
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(C_PORT);
addr.sin_addr.s_addr = inet_addr(C_IP);
if(connect(sockfd,(struct sockaddr*)&addr,sizeof(struct sockaddr))<0)
{
perror("connect error\n");
exit(0);
}
- 客户端向服务器发起请求后,服务器接收连接,并建立服务器与客户端之间的连接,返回新的套接字。
while(1)
{
struct sockaddr_in fromaddr;
int len = sizeof(fromaddr);
int fd = accept(sockfd,(struct sockaddr*)&fromaddr,&len);
if(fd<0)
{
perror("accept error\n");
continue;
}
。。。。。。
}
- 服务器与客户端建立连接后创建一个线程用于与客户端通信。
pthread_t tid;
pthread_create(&tid,0,(void*)fun,&msg);
- 服务器创建的线程用于完成与客户端的同信,具体如下:
- 获取当前时间,主要用来记录客户端登陆,退出,发送信息的时间
void gettime(char *buf)
{
time_t timep;
struct tm *p;
memset(buf,0,sizeof(buf));
time(&timep);
p = localtime(&timep);
sprintf(buf,"%d-%d-%d %d:%d:%d\n", (1900 + p->tm_year), ( 1 + p->tm_mon), p->tm_mday,(p->tm_hour), (p->tm_min), p->tm_sec);
}
- 接受客户端信息,存入日志文件,并转发给其他客户端:
void *fun(struct msg* agv)
{
int fd = agv->fd;
char name[20];
int a=0;
while(1)
{
char buf[1024];
memset(buf,0,sizeof(buf));
recv(fd,buf,sizeof(buf),0);
if(strncmp(buf,"end",3)==0)
{
char str1[100];
memset(str1,0,sizeof(str1));
sprintf(str1,"%s退出系统",name);
save(str1);
continue;
}
if(a)
{
save(buf);
SendAll(buf,fd);
}
else
{
char str[200];
sprintf(str,"IP为%s的%s登录系统",inet_ntoa(agv->sin_addr),buf);
save(str);
sprintf(name,"%s",buf);
}
a=1;
}
}
- 将传入的字符串存入文件
void save(char* buf)
{
int fd1;
char buf1[2000];
char time[100];
memset(time,0,sizeof(time));
memset(buf1,0,sizeof(buf1));
if(strlen(buf)!=0)
{
gettime(time);
sprintf(buf1,"%s%s",time,buf);
fd1=open("log",O_CREAT|O_WRONLY|O_APPEND,0666);
write(fd1,buf1,strlen(buf1));
char* a="\n";
write(fd1,a,strlen(a));
}
}
- 将传入的字符串转发给其他客户端
void SendAll(char *buf,int fd)
{
for(int i=0;i<conn_size;i++)
{
if(fd!=fds[i]&&fds[i]!=0)
{
send(fds[i],buf,strlen(buf),0);
}
}
buf='\0';
}
- 服务器主线程通过while(1)循环保持一直存在,等待其他客户端连接。
- 客户端输入姓名,作为在聊天室中的标识。
printf("请输入姓名:\n");
char name[20];
scanf("%s",name);
send(sockfd,name,strlen(name),0);
- 客户端与服务器建立连接后创建一个新线程。
pthread_t tid;
pthread_create(&tid,0,fun,&sockfd);
- 新线程用于与接收服务器转发的信息。
void* fun(void* agv)
{
int fd=*(int*)agv;
while(1)
{
char buf[1024];
memset(buf,0,sizeof(buf));
recv(fd,buf,sizeof(buf),0);
printf("%s\n",buf);
}
}
- 主线程用于向服务器发送信息。
while(1)
{
char buf[1024];
char buf1[1144];
memset(buf1,0,sizeof(buf1));
memset(buf,0,sizeof(buf));
scanf("%s",buf);
if(strcmp(buf,"end")==0)
{
send(sockfd,buf,strlen(buf),0);
exit(0);
}
sprintf(buf1,"%s:%s",name,buf);
send(sockfd,buf1,strlen(buf1),0);
}
#include<stdio.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<pthread.h>
#include<string.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<time.h>
#define S_IP "127.0.0.1"
#define S_PORT 44554
#define conn_size 100
struct msg{
int fd;
struct in_addr sin_addr;
};
int count=0;
int fds[conn_size];
void gettime(char *buf)
{
time_t timep;
struct tm *p;
memset(buf,0,sizeof(buf));
time(&timep);
p = localtime(&timep);
sprintf(buf,"%d-%d-%d %d:%d:%d\n", (1900 + p->tm_year), ( 1 + p->tm_mon), p->tm_mday,(p->tm_hour), (p->tm_min), p->tm_sec);
}
void SendAll(char *buf,int fd)
{
for(int i=0;i<conn_size;i++)
{
if(fd!=fds[i]&&fds[i]!=0)
{
send(fds[i],buf,strlen(buf),0);
}
}
buf='\0';
}
void save(char* buf)
{
int fd1;
char buf1[2000];
char time[100];
memset(time,0,sizeof(time));
memset(buf1,0,sizeof(buf1));
if(strlen(buf)!=0)
{
gettime(time);
sprintf(buf1,"%s%s",time,buf);
fd1=open("log",O_CREAT|O_WRONLY|O_APPEND,0666);
write(fd1,buf1,strlen(buf1));
char* a="\n";
write(fd1,a,strlen(a));
}
}
void *fun(struct msg* agv)
{
//int fd = *(int *)agv;
int fd = agv->fd;
char name[20];
int a=0;
while(1)
{
char buf[1024];
memset(buf,0,sizeof(buf));
recv(fd,buf,sizeof(buf),0);
if(strncmp(buf,"end",3)==0)
{
char str1[100];
memset(str1,0,sizeof(str1));
sprintf(str1,"%s退出系统",name);
save(str1);
continue;
}
if(a)
{
save(buf);
SendAll(buf,fd);
}
else
{
//char *inet_ntoa(struct in_addr in)
char str[200];
//sprintf(str,"IP为%u的%s登录系统",agv->sin_addr.s_addr,buf);
sprintf(str,"IP为%s的%s登录系统",inet_ntoa(agv->sin_addr),buf);
save(str);
sprintf(name,"%s",buf);
}
a=1;
}
}
int main()
{
int sockfd;
if((sockfd = socket(PF_INET,SOCK_STREAM,0))<0)
{
perror("socket error\n");
exit(0);
}
struct sockaddr_in addr;
addr.sin_family = PF_INET;
addr.sin_port = htons(S_PORT);
addr.sin_addr.s_addr = inet_addr(S_IP);
if(bind(sockfd,(struct sockaddr *)&addr,sizeof(addr)) < 0)
{
perror("bind error\n");
exit(1);
}
if (listen(sockfd,conn_size) < 0)
{
perror("listen error\n");
exit(1);
}
//-------------------------------------------------------------
while(1)
{
struct sockaddr_in fromaddr;
int len = sizeof(fromaddr);
int fd = accept(sockfd,(struct sockaddr*)&fromaddr,&len);
if(fd<0)
{
perror("accept error\n");
continue;
}
fds[count]=fd;
count++;
struct msg msg;
msg.fd=fd;
msg.sin_addr.s_addr=fromaddr.sin_addr.s_addr;
pthread_t tid;
pthread_create(&tid,0,(void*)fun,&msg);
if (conn_size == count)
{
char* str = "对不起,聊天室已经满了!";
send(fd,str,strlen(str),0);
close(fd);
}
}
return 0;
}
2.客户端代码
#include<stdio.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<pthread.h>
#include<string.h>
#include<errno.h>
#include <time.h>
#define C_IP "127.0.0.1"
#define C_PORT 44554
void* fun(void* agv)
{
int fd=*(int*)agv;
while(1)
{
char buf[1024];
memset(buf,0,sizeof(buf));
recv(fd,buf,sizeof(buf),0);
printf("%s\n",buf);
}
}
int main()
{
int sockfd;
if((sockfd=socket(PF_INET,SOCK_STREAM,0))<0)
{
perror("socket error\n");
exit(0);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(C_PORT);
addr.sin_addr.s_addr = inet_addr(C_IP);
if(connect(sockfd,(struct sockaddr*)&addr,sizeof(struct sockaddr))<0)
{
perror("connect error\n");
exit(0);
}
printf("请输入姓名:\n");
char name[20];
scanf("%s",name);
send(sockfd,name,strlen(name),0);
pthread_t tid;
pthread_create(&tid,0,fun,&sockfd);
while(1)
{
char buf[1024];
char buf1[1144];
memset(buf1,0,sizeof(buf1));
memset(buf,0,sizeof(buf));
scanf("%s",buf);
if(strcmp(buf,"end")==0)
{
send(sockfd,buf,strlen(buf),0);
exit(0);
}
sprintf(buf1,"%s:%s",name,buf);
send(sockfd,buf1,strlen(buf1),0);
}
return 0;
}