嵌入式每日学习心得 基于TCP/IP的聊天室程序
2017-09-09 17:19
323 查看
//cilent.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <pthread.h> void* rcv_fun(void* arg); int main(int argc,char *argv[]) { //FILE* p =fopen("1.txt","w+"); //fclose(p); int sock = socket(AF_INET, SOCK_STREAM, 0); int opt_val = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof(opt_val)); struct sockaddr_in myaddr; myaddr.sin_family = AF_INET; myaddr.sin_addr.s_addr = INADDR_ANY; myaddr.sin_port = htons(1234); if(-1 == bind(sock,(struct sockaddr*)&myaddr, sizeof(myaddr))) { perror("bind"); exit(-1); } struct sockaddr_in srv_addr; srv_addr.sin_family = AF_INET; srv_addr.sin_addr.s_addr = inet_addr(argv[1]); srv_addr.sin_port = htons(atoi(argv[2])); if(-1 == connect(sock,(struct sockaddr*)&srv_addr,sizeof(srv_addr))) { perror("connect"); exit(-1); } pthread_t tid; int num; char buf[2048]; struct timeval rcv_timeout; rcv_timeout.tv_sec = 0; rcv_timeout.tv_usec = 100000; //setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &rcv_timeout, sizeof(rcv_timeout)); if(0 != pthread_create(&tid, NULL, rcv_fun, (void*)sock)) { perror("pthread_create"); exit(-1); } while(1) { //printf("本机:"); //scanf("%s",buf); //fgets(buf,100,stdin); gets(buf); if(-1 == send(sock,buf,strlen(buf),0)) { perror("send"); } fflush(stdin); } close(sock); return 0; } void* rcv_fun(void* arg) { char buf[2048]; int num; pthread_detach(pthread_self()); int sock =(int)arg; while(1) { num = recv(sock ,buf, sizeof(buf), 0); if(num <= 0) { printf("接受数据失败,连接断开!\n"); } else { buf[num] = '\0'; printf("%s\n",buf); } } return NULL; } //server.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> #include <sys/types.h> #include <sys/socket.h> #include <signal.h> #include <unistd.h> void* con_fun(void* arg); struct buff { int sock_in; struct sockaddr_in addr; }; pthread_mutex_t m; int main() { FILE* p =fopen("1.txt","w+"); fclose(p); signal(SIGPIPE,SIG_IGN); pthread_mutex_init(&m,NULL); int sock_fp=socket(AF_INET,SOCK_STREAM,0); int opt_val; setsockopt(sock_fp,SOL_SOCKET,SO_REUSEADDR,&opt_val,sizeof(opt_val)); struct sockaddr_in myaddr; myaddr.sin_family=AF_INET; myaddr.sin_addr.s_addr=INADDR_ANY; myaddr.sin_port=htons(9999); if(-1==bind(sock_fp,(struct sockaddr*)&myaddr,sizeof(myaddr))) { perror("bind"); exit(-1); } if(-1==listen(sock_fp,5)) { perror("listen"); exit(-1); } pthread_t tid; int sock_conn; struct sockaddr_in silent_addr; socklen_t len; int tag[]={0}; FILE* q; while(1) { len=sizeof(silent_addr); struct buff* s1=(struct buff*)malloc(sizeof(struct buff)); sock_conn=accept(sock_fp,(struct sockaddr*)&silent_addr,&len); printf("sock_conn:%d",sock_conn); if(sock_conn==-1) { perror("accept"); continue; } s1->sock_in=sock_conn; s1->addr=silent_addr; pthread_mutex_lock(&m); FILE* fp=fopen("1.txt","a+"); int i=0,j=0; q=fopen("1.txt","r"); while(!feof(q)) { fscanf(q,"%d\n",&tag[i++]); } for(j=0;j<=i;j++) { if(s1->sock_in == tag[j]) break; 4000 if(j==i) fprintf(fp,"%d\n",sock_conn); } //fprintf(fp,"%d\n",sock_conn); fclose(fp); fclose(q); pthread_mutex_unlock(&m); if(0!=pthread_create(&tid,NULL,con_fun,s1)) { perror("pthread_create"); close(sock_conn); } } system("rm 1.txt"); close(sock_fp); pthread_mutex_destroy(&m); return 0; } void* con_fun(void* arg) { pthread_detach(pthread_self()); struct buff s1=*((struct buff*)arg); free(arg); char msg[100]; char buf[100]; int ret; int sock; while(1) { ret=recv(s1.sock_in,msg,sizeof(msg)-1,0); if(ret>0) { msg[ret]='\0'; sprintf(buf,"%s:%d:%s",inet_ntoa(s1.addr.sin_addr),ntohs(s1.addr.sin_port),msg); } else { printf("接收失败\n"); break; } pthread_mutex_lock(&m); FILE* fp=fopen("1.txt","r"); while(!feof(fp)) { fscanf(fp,"%d\n",&sock); printf("sock:%d\n",sock); if(sock!=s1.sock_in) send(sock,buf,strlen(buf),0); } fclose(fp); pthread_mutex_unlock(&m); } close(s1.sock_in); return NULL; }
基于TCP协议编程{
//TCP编程步骤
服务器端 客户端
1.创建套接字 socket() 1.创建套接字 socket()
2.套接字与端口的绑定 bind() (客户端也可套接字和端口绑定,但一般没有这个必要)
3.设置监听队列 listen()
4.接收客户端连接 accept() 2.连接服务器 connect()
5.收发数据 recv() write() 3.收发数据
6.断开 close() 4.断开
一方调用close函数只是断开一半连接
设置地址复用{
int optval=1;
setsockopt(sock_listen,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval));
setsockopt: 设置套接字的某个属性值
设置sock_listen套接字的SO_REUSEADDR属性值为1,以让它可以地址复用
}
2.基于TCP协议通信中的粘包问题{
粘包问题产生的原因:
1.发送方造成的:TCP协议为了提升传输效率,在默认情况下,在我们调用send函数发送一份数据时,系统并不会将这份数据立即打包发送到网络上去,而只是将这份数据存放到网络发送缓冲区中,然后等待一小段时间,如果在这段时间之内我们又调用send函数发送数据,那么系统会进行同样的处理,如果我们在这段时间之内没有对外发送数据,那么系统会将网络发送缓冲区中的所有数据打成一个数据包发送到网络上去
2.接收方造成的:如果接收方不及时接收对方发送过来的多个数据包,那么这多个数据包将会在接收方的网络接收缓冲区中合并在一起,此时如果接收方提供一个足够大的缓冲区来接收这些数据,那么将会一次性接收到所有数据包的数据
粘包问题解决方案:
1.增加连续发送间隔时间(usleep):非常草根,严重影响效率
2.取消TCP内部的那个优化算法:不推荐,不是所有平台支持
3.加包头或包尾
4.应答式通信
}
相关文章推荐
- 【tcp-ip学习总结】基于udp的多人聊天室,带有登录注册功能
- 嵌入式每日学习心得 网络通信技术(TCP)
- 【tcp-ip学习总结】使用tcp协议实现简单的通信小程序
- 【LIUNX】---TCP/IP学习与实践[基于原始套接字的rootkit]
- C++基于TCP/IP简单的客户端、服务器通信程序实例
- 嵌入式每日学习心得2017.08.01
- Time protocol实现的基于TCP/IP的网络对时程序
- TCP/IP实验报告(一):基于TCP的客户/服务器通信程序实例
- tcp/ip学习心得(2)
- 嵌入式每日学习心得2017.08.07
- C++基于TCP/IP简单的客户端、服务器通信程序实例
- TCP/IP 学习心得
- 嵌入式每日学习心得2017.07.13
- 嵌入式每日学习心得2017.07.21
- 嵌入式每日学习心得2017.07.14
- 基于TCP/IP 协议的简单C/S程序
- 基于TCP/IP的简单的聊天程序
- 嵌入式每日学习心得2017.07.24
- 嵌入式每日学习心得2017.07.25
- 嵌入式每日学习心得2017.07.10