服务器端:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <netdb.h>
#include <pthread.h>
/*线程执行函数的读写*/
void *thr_fn(void *arg)
{
int size,j;
char recv_buf[1024];
int *parg=(int*)arg;
int new_fd=*parg;
printf("new_fd=%d \n",new_fd);
while((size=read(new_fd,recv_buf,1024))>0)
{
if(recv_buf[0]=='@')
break;
printf("Message from client (%d):%s \n",size,recv_buf);
for(j=0;j<size;j++)
recv_buf[j]=toupper(recv_buf[j]);//转换为大写英文字母
write(new_fd,recv_buf,size);
memset(recv_buf,0,sizeof(recv_buf));
}
close(new_fd);
return 0;
}
int main(int argc,char **argv)
{
socklen_t clt_addr_len;// 数据类型"socklen_t"和int应该具有相同的长度.
int listen_fd;
int com_fd;
int ret;
int i;
//static char recv_buf[1024];//???
int len;
int port;
pthread_t tid;
struct sockaddr_in clt_addr;
struct sockaddr_in srv_addr;
/*服务器端运行时要给出端口信息,即监听端口*/
if(argc!=2)
{
printf("Usage:%s port \n",argv[0]);
return 1;
}
/*获得输入的端口*/
port=atoi(argv[1]);//功 能: 把字符串转换成整型数.名字来源:array to integer 的缩写
/*创建套接字用于服务器的监听*/
listen_fd=socket(PF_INET,SOCK_STREAM,0);
if(listen_fd<0)
{
perror("cannot create listening socket");
return 1;
}
/*填充服务器端套节字*/
memset(&srv_addr,0,sizeof(srv_addr));
srv_addr.sin_family=AF_INET;
srv_addr.sin_addr.s_addr=htonl(INADDR_ANY);//??
srv_addr.sin_port=htons(port);
/*绑定listen_fd*/
ret=bind(listen_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));
if(ret==-1)
{
perror("cannot listen the client connect request ");
return 1;
}
/*监听指定端口,连接5个客户端*/
ret=listen(listen_fd,5);
if(ret==-1)
{
perror("cannot listen the client connect request");
close(listen_fd);
return 1;
}
/*对每个连接来的客户端创建一个线程,单独与其通信*/
while(1)
{
len=sizeof(clt_addr);
com_fd=accept(listen_fd,(struct sockaddr*)&clt_addr,&len);
if(com_fd<0)
{
if(errno==EINTR)// 由于信号中断返回
{
continue;
}
else
{
perror("cannot accept client connect request");
close(listen_fd);
return 1;
}
}
printf("com_fd=%d \n",com_fd);
if((pthread_create(&tid,NULL,thr_fn,&com_fd))==-1)
{
perror("pthread_create error");
close(listen_fd);
close(com_fd);
return 1;
}
}
return 0;
}
/*
AF 表示ADDRESS FAMILY 地址族
PF 表示PROTOCOL FAMILY 协议族
*/
/*
C类型字符串 后面有一个 '\0 ' 作为 结尾标示符隐含加入。
sizeof(a) 就包括了 '\0 '
而strlen(a) 没有将 '\0 '计算在内。
*/
/*
in_addr_t inet_addr(const char* strptr);
返回:若字符串有效则为32位二进制网络字节序的IPV4地址,否则为INADDR_NONE
struct in_addr{
in_addr_t s_addr;
}
*/
客户端:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netdb.h>
#include <unistd.h>
int main(int argc,int *argv[])
{
int connect_fd;
int ret;
char snd_buf[1024];
int i;
int port;
int len;
static struct sockaddr_in srv_addr; //??
if(argc!=3)
{
perror("Usage: lack of arguments");
return 1;
}
/*获得输入端口*/
port=atoi(argv[2]);
/*创建套节字用于客户端的连接*/
connect_fd=socket(PF_INET,SOCK_STREAM,0);
if(connect_fd<0)
{
perror("cannot create communication socket");
return 1;
}
/*填充服务器的套节字*/
memset(&srv_addr,0,sizeof(srv_addr));
srv_addr.sin_family=AF_INET;
srv_addr.sin_addr.s_addr=inet_addr(argv[1]);//??32位的地址,
srv_addr.sin_port=htons(port);
/*连接指定的服务器*/
ret=connect(connect_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));
if(ret==-1)
{
perror("cannot connect to the server");
close(connect_fd);
return 1;
}
memset(snd_buf,0,1024);
/*向服务器发送,读取服务器发来的消息*/
while(1)
{
write(STDOUT_FILENO,"input message:",14);
memset(snd_buf,0,sizeof(snd_buf));//?
len=read(STDIN_FILENO,snd_buf,1024);
if(len>0)
write(connect_fd,snd_buf,len);
len=read(connect_fd,snd_buf,len);
if(len>0)
printf("Message from server:%s ",snd_buf);
if(snd_buf[0]=='@')
break;
}
close(connect_fd);
return 0;
}
注:当有客户连接时,服务器端为每个连接创建一个线程进行读写。
qust@qust-K42JZ:~/test$ gcc server_thread.c -o server_thread -lpthread
qust@qust-K42JZ:~/test$ ./server_thread 3334
cannot listen the client connect request : Address already in use
qust@qust-K42JZ:~/test$ ./server_thread 3333
qust@qust-K42JZ:~/test$ ./client_thread 211.87.147.61 3333
input message:ggggggggggggg
Message from server:GGGGGGGGGGGGG