TCP套接字网络编程实例(二)
采用多线程实现客户端和服务器的聊天功能。OK,上代码。
1.客户端部分:
/*
* 文件:tcp_client.c
* 内容:利用TCP实现客户端和服务器的实时聊天。
* 注 :服务器的端口号及IP,客户端的端口号及IP的输入通过main函数的argc和argv来实现。
* 未输入端口号的话使用默认端口号,服务器为1111,客户端为2222。
* 编译:gcc tcp_client.c -o cli -lpthread
* 运行:./cli 127.0.0.1 7788(注:这个是服务器端的地址和端口号)
*/
#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#include<string.h>
#include <arpa/inet.h>
#include<errno.h>
#include<time.h>
#include<pthread.h>
#define IP "127.0.0.1"
#define SPORT 1111
#define CPORT 2222
#define MAXLEN 1024
void* myrecv(void* arg)
{
int sock_fd = 0,len = 0;
char buf[MAXLEN] = {'\0'};
time_t t;
sock_fd = *((int*)arg);
while(1)
{
memset(buf,'\0',sizeof(buf)-1);
len = recv(sock_fd,buf,sizeof(buf) - 1,0);
if(len > 0)
{
t = time(NULL);
printf("**********************************\n");
printf("&server:%s\n",buf);
printf("**********************************\n");
printf("@%s\n",ctime(&t));
}
else if(len < 0)
{
printf("recv msg errno,errno code = %d,errno msg = %s\n",errno,strerror(errno));
break;
}
else
{
printf("connect server error,it will be quit in 3 seconds later...\n");
sleep(3);
exit(EXIT_FAILURE);
}
}
}
void* mysend(void* arg)
{
int sock_fd = 0,len = 0;
char buf[MAXLEN] = {'\0'};
sock_fd = *((int*)arg);
while(1)
{
memset(buf,'\0',sizeof(buf));
gets(buf);
if(!strncasecmp(buf,"quit",4))
{
printf("I will close the connect ...\n");
sleep(1);
exit(EXIT_FAILURE);
}
len = send(sock_fd,buf,strlen(buf),0);
if(len < 0)
{
printf("msg is:%s,send failer,errno is %d,errno message is:%s\n",buf,errno,strerror(errno));
break;
}
}
}
int main(int argc,char* argv[])
{
int pid = 0,sock_fd = 0;
socklen_t len;
struct sockaddr_in their_addr;
unsigned int their_port;
char buf[MAXLEN] = {0};
pthread_t pthread1,pthread2;
//创建socket
if((sock_fd = socket(AF_INET,SOCK_STREAM,0)) < 0)
{
perror("socket error");
exit(EXIT_FAILURE);
}
//发送连接服务器的请求
memset(&their_addr,0,sizeof(their_addr));
their_addr.sin_family = AF_INET;
if(argv[2] && argc >= 3)
their_port = atoi(argv[2]);
else
their_port = SPORT;
their_addr.sin_port = htons(their_port);
if(argv[1] && argc >=2)
{
if(inet_aton(argv[1],(struct in_addr *)&their_addr.sin_addr.s_addr) == 0)
{
perror("argv[1]");
exit(EXIT_FAILURE);
}
}
else
their_addr.sin_addr.s_addr = inet_addr(IP);
if(connect(sock_fd,(struct sockaddr*)(&their_addr),sizeof(their_addr)) == -1)
{
perror("connect error");
exit(EXIT_FAILURE);
}
printf("==============================================\n");
printf("connect success!\n");
printf("if you want to leave,please print 'quit'.\n");
printf("==============================================\n");
pthread_create(&pthread1,NULL,myrecv,(void*)&sock_fd);
pthread_create(&pthread2,NULL,mysend,(void*)&sock_fd);
pthread_join(pthread1,NULL);
pthread_join(pthread2,NULL);
close(sock_fd); //关闭套接字
return 1;
}
2.服务器部分:
/*
* 文件:tcp_server.c
* 内容:利用TCP实现客户端和服务器的实时聊天。
* 注 :服务器的端口号及IP,客户端的端口号及IP的输入通过main函数的argc和argv来实现。
* 未输入端口号的话使用默认端口号,服务器为1111,客户端为2222。
* 编译:gcc tcp_server.c -o ser -lpthread
* 运行:./ser 127.0.0.1 7788 5
*/
#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<time.h>
#include<errno.h>
#include<pthread.h>
#include<arpa/inet.h>
#define SPORT 1111
#define CPORT 2222
#define IP "127.0.0.1"
#define MAXLEN 1024
struct network_info
{
struct sockaddr addr;
int addr_len;
int sock;
}target = {0,0,0};
void* myrecv(void* arg)
{
int new_fd = 0,len = 0;
char buf[MAXLEN] = {'\0'};
time_t t;
struct network_info netinfo;
netinfo = *((struct network_info*)arg);
new_fd = netinfo.sock;
while(1)
{
memset(buf,'\0',sizeof(buf)-1);
len = recv(new_fd,buf,sizeof(buf) - 1,0);
if(len > 0)
{
t = time(NULL);
printf("&client:%s @%s\n",buf,ctime(&t));
}
else if(len < 0)
{
printf("recv msg error,error code = %d,error msg = %s\n",errno,strerror(errno));
break;
}
else
{
printf("client is quit\n");
close(new_fd);
break;
}
}
}
void* mysend(void* arg)
{
int new_fd = 0,len = 0;
char buf[MAXLEN] = {'\0'};
struct network_info netinfo;
netinfo = *((struct network_info*)arg);
new_fd = netinfo.sock;
while(1)
{
memset(buf,'\0',sizeof(buf));
gets(buf);
if(!strncasecmp(buf,"quit",4))
{
printf("I will close the connect\n");
close(new_fd);
exit(EXIT_FAILURE);
}
len = sendto(new_fd,buf,strlen(buf),0,(struct sockaddr*)(&(netinfo.addr)),netinfo.addr_len);
if(len < 0)
{
printf("msg is:%s,send failer,errno is %d,errno message is:%s\n",buf,errno,strerror(errno));
break;
}
}
}
int main(int argc,char* argv[])
{
int pid = 0,sock_fd = 0,new_fd = 0;
socklen_t len;
struct sockaddr_in self_addr,their_addr;
unsigned int myport,lisnum;
char buf[MAXLEN] = {'\0'};
char ip[17] = {'\0'};
time_t t;
pthread_t pthread1,pthread2;
if(argv[2] && argc >=3)
myport = atoi(argv[2]);
else
myport = SPORT;
if(argv[3] && argc >= 4)
lisnum = atoi(argv[3]);
else
lisnum = 3;
//创建套接字
sock_fd = socket(AF_INET,SOCK_STREAM,0);
if(sock_fd < 0)
{
perror("socket error");
exit(EXIT_FAILURE);
}
//绑定自己的端口号
memset(&self_addr,0,sizeof(self_addr));
self_addr.sin_family = AF_INET;
self_addr.sin_port = htons(myport);
if(argv[1])
self_addr.sin_addr.s_addr = inet_addr(argv[1]);
else
self_addr.sin_addr.s_addr = INADDR_ANY;
if(bind(sock_fd,(struct sockaddr*)&self_addr,sizeof(self_addr)) == -1)
{
perror("bind error");
exit(EXIT_FAILURE);
}
//监听
if(listen(sock_fd,lisnum) == -1)
{
perror("listen error");
exit(EXIT_FAILURE);
}
//接受客户端的连接请求
memset(&their_addr,0,sizeof(their_addr));
len = sizeof(their_addr);
printf("wait for connect\n");
while(1)
{
if((new_fd = accept(sock_fd,(struct sockaddr*)&their_addr,&len)) == -1)
{
printf("len=%d,new_fd=%d\n",len,new_fd);
perror("accept error");
exit(EXIT_FAILURE);
}
printf("=====================================================================\n");
printf("client connect ok\n");
printf("though i am a server,but if you want to shutdown,please print 'quit'.\n");
printf("=====================================================================\n");
memcpy(&(target.addr),&(their_addr),len);
target.addr_len = len;
target.sock = new_fd;
//创建线程用于进程间通信
pthread_create(&pthread1,NULL,myrecv,(void*)&target);
pthread_create(&pthread2,NULL,mysend,(void*)&target);
}
pthread_join(pthread1,NULL);
pthread_join(pthread2,NULL);
close(new_fd);
close(sock_fd); //关闭套接字
return 0;
}
结果:(交叉编译后也可用,那么加上串口编程,加上select,将结构体改为字符串,字符串数据加IP地址等等然后以专有协议形成“报文”,然后和设备以相同协议通讯,似乎。。。)