#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int startup(int _port,const char* _ip)
{
int sock=socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
perror("socket");
exit(1);
}
int opt=1;
if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt))<0)
{
perror("setsockopt");
exit(2);
}
struct sockaddr_in local;
local.sin_family=AF_INET;
local.sin_port=htons(_port);
local.sin_addr.s_addr=inet_addr(_ip);
socklen_t len=sizeof(local);
if(bind(sock,(struct sockaddr*)&local,len)<0)
{
perror("bind");
exit(2);
}
if(listen(sock,5)<0)
{
perror("listen");
exit(3);
}
return sock;
}
int main(int argc,char* argv[])
{
if(argc!=3)
{
printf("Usage: [local_ip] [local_port]",argv[0]);
return 3;
}
int listen_socket=startup(atoi(argv[2]),argv[1]);
struct sockaddr_in remote;
socklen_t len=sizeof(struct sockaddr_in);
while(1)
{
int socket=accept(listen_socket,(struct sockaddr*)&remote,&len);
if(socket<0)
{
perror("accept");
continue;
}
pid_t pid=fork();
if(pid==0)
{
if(fork()>0)
{
exit(1);
}
char buf[1024];
while(1)
{
ssize_t _s=read(socket,buf,sizeof(buf)-1);
if(_s>0)
{
buf[_s]=0;
printf("client# %s\n",buf);
}
else
{
printf("client is quit!\n");
break;
}
printf("client,ip:%s,port:%d\n",inet_ntoa(remote.sin_addr)\
,ntohs(remote.sin_port));
}
}
else if(pid>0)
{
close(socket);
waitpid(-1,NULL,WNOHANG);
}
else
{
perror("fork");
exit(2);
}
}
return 0;
}
這份代碼修改了兩個地方:
- 它是用來解決什麼問題的?
- 不這樣做會產生怎樣的後果?
- 函數原型的說明。
實現方法:
(1)主線程中創建出一個新線程,新線程的執行函數是讀取信息,類似於上邊的多進程間的通信。
#include<stdio.h>
#include<assert.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>
#include<stdlib.h>
int startup(int _port,char* _ip)
{
assert(_ip);
int sock=socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
perror("socket");
exit(2);
}
struct sockaddr_in local;
local.sin_family=AF_INET;
local.sin_port=htons(_port);
local.sin_addr.s_addr=inet_addr(_ip);
socklen_t len=sizeof(local);
int opt = 1;
int stat= setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
if(bind(sock,(struct sockaddr*)&local,len)<0)
{
perror("bind");
exit(3);
}
if(listen(sock,5)<0)
{
perror("listen");
exit(4);
}
return sock;
}
void* handler_fd(void* arg)
{
int sock=*((int*)arg);
pthread_detach(pthread_self());
char buf[1024];
while(1)
{
ssize_t _s=read(sock,buf,sizeof(buf)-1);
if(_s>0)
{
buf[_s-1]=0;
printf("Client# %s\n",buf);
}
else
{
printf("Client quit!");
close(sock);
break;
}
}
int main(int argc,char*argv[])
{
if(argc!=3)
{
printf("Usage:%s,[local_ip] [local_port]\n",argv[0]);
exit(1);
}
int listen_sock=startup(atoi(argv[2]),argv[1]);
struct sockaddr_in peer;
socklen_t len=sizeof(peer);
while(1)
{
int sock=accept(listen_sock,(struct sockaddr*)&peer,&len);
if(sock<0)
{
perror("accept");
continue;
}
pthread_t tid;
int ret=pthread_create(&tid,NULL,handler_fd,&sock);
if(ret<0)
{
printf("pthread create failed!\n");
exit(5);
}
pthread_detach(tid);
}
return 0;
}
client.c不用改變,有關進程,線程套接字的通信就介紹到此。