基于TCP的聊天室小程序

  1. 建立socket:

建立一个适用于ipv4协议的流式套接字

int sockfd;

    if((sockfd = socket(PF_INET,SOCK_STREAM,0))<0)

    {

perror("socket error\n");

exit(0);

}

  1. 服务器端套接字与本地地址相连:

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);

}

  1. 服务器端监听请求队列

设置队列大小为conn_size

if (listen(sockfd,conn_size) < 0)

    {

       perror("listen error\n");

       exit(1);

    }

  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);

 }

  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;

         }

。。。。。。

}

  1. 服务器与客户端建立连接后创建一个线程用于与客户端通信。

pthread_t tid;

      pthread_create(&tid,0,(void*)fun,&msg);

 

  1. 服务器创建的线程用于完成与客户端的同信,具体如下:
  1. 获取当前时间,主要用来记录客户端登陆,退出,发送信息的时间

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);

}

  1. 接受客户端信息,存入日志文件,并转发给其他客户端:

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;

}

}

  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));

}

}

 

  1. 将传入的字符串转发给其他客户端

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';

}

  1. 服务器主线程通过while(1)循环保持一直存在,等待其他客户端连接。
  2. 客户端输入姓名,作为在聊天室中的标识。

printf("请输入姓名:\n");

     char name[20];

     scanf("%s",name);

       send(sockfd,name,strlen(name),0);

  1. 客户端与服务器建立连接后创建一个新线程。

pthread_t tid;                                  

      pthread_create(&tid,0,fun,&sockfd);

  1. 新线程用于与接收服务器转发的信息。

     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);

}

}

  1. 主线程用于向服务器发送信息。

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;
}

 

 

猜你喜欢

转载自blog.csdn.net/qq_40663637/article/details/84727718