C语言用socket通信在linux下实现简单的server端到client端的通信,涉及到多个client端的话,server端用子进程实现,client端的接收和发送分别用两个线程来实现。
server.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#define PORT 4444
#define BACKLOG 10
#define MAXSIZE 2048
void *thread_writeall(void *args);
int client_fd_all[BACKLOG]={0};
int iClient=0;
//不阻塞等待的情况下,捕获子进程退出信号,避免子进程僵死
int sig_chld(int singno)
{
pid_t pid;
int stat;
while( (pid = waitpid(-1, &stat, WNOHANG)) > 0 ) {
printf( "child %d exit\n", pid );
}
}
int main()
{
static int thread_flag = 0;
int sockfd,client_fd;
struct sockaddr_in my_addr;
struct sockaddr_in remote_addr;
char readBuff[MAXSIZE],writeBuff[MAXSIZE];
signal(SIGCHLD,&sig_chld);
//创建套接字
if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1) {
printf("socket create failed!\n");
return -1;
}
my_addr.sin_family = AF_INET; //ipv4
my_addr.sin_port = htons(PORT); //port
my_addr.sin_addr.s_addr = INADDR_ANY; //localhost
memset(&my_addr.sin_zero,0,8);
//服务端用bind将套接字与ip地址和端口绑定起来
if (bind(sockfd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) == -1) {
printf("bind error!\n");
return -1;
}
//监听端口(服务端被动监听)
if (listen(sockfd, BACKLOG) == -1) {
printf("listen error\n");
return -1;
}
printf("listen success\n");
while(1){
//accept形成阻塞等待,直到接收client端请求,返回新的套接字和client通信
int sin_size = sizeof(struct sockaddr_in);
client_fd = accept(sockfd, (struct sockaddr*)&remote_addr,(socklen_t *)&sin_size);
client_fd_all[iClient++]=client_fd;
printf("Received a connection from %s\n", (char *)inet_ntoa(remote_addr.sin_addr));
//创建发往客户端的子线程
if(!thread_flag++){
pthread_t tid;
pthread_attr_t thread_attr;
if (pthread_attr_init(&thread_attr))
{
printf("pthread_attr_init() failure: %s\n", strerror(errno));
return -1;
}
//设置子线程与主线程为相分离的关系
if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED))
{
printf("pthread_attr_setdetachstate() failure: %s\n", strerror(errno));
return -1;
}
pthread_create(&tid, &thread_attr, thread_writeall, &client_fd);
}
if(fork() == 0){
while(1){
//从套接字读入内存
memset(readBuff,0,sizeof(readBuff));
read(client_fd,readBuff,MAXSIZE);
printf("%s:[%s]\n",(char *)inet_ntoa(remote_addr.sin_addr),readBuff);
//数据写入套接字,发往客户端
memset(writeBuff,0,sizeof(writeBuff));
sprintf(writeBuff,"Hello client ,I am server");
write(client_fd,writeBuff,MAXSIZE);
}
close(client_fd);
}
}
close(sockfd);
}
void *thread_writeall(void *args)
{
//int *client_fd = (int *)args;
char writeBuff[MAXSIZE];
while(1){
//数据写入套接字,发往客户端
memset(writeBuff,0,sizeof(writeBuff));
fgets(writeBuff,MAXSIZE,stdin);
for(int i=0;i<iClient;i++){
write(client_fd_all[i],writeBuff,MAXSIZE);
}
printf("writeBuff:[%s]\n",writeBuff);
}
printf("thread_writeall exit\n");
return NULL;
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#define PORT 4444
#define BACKLOG 10
#define MAXSIZE 2048
#define SERVERIP "192.168.0.30"
void *thread_read(void *args);
int main()
{
int sockfd;
struct sockaddr_in serv_addr;
char readBuff[MAXSIZE],writeBuff[MAXSIZE];
//创建套接字
if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1) {
printf("socket create failed!\n");
return -1;
}
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family = AF_INET; //ipv4
serv_addr.sin_port = htons(PORT); //port
serv_addr.sin_addr.s_addr = inet_addr(SERVERIP); //server
//客户端用connect将套接字与ip地址和端口连接
if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(struct sockaddr)) == -1) {
printf("connect error!\n");
return -1;
}
//创建读服务端的子线程
pthread_t tid;
pthread_attr_t thread_attr;
if (pthread_attr_init(&thread_attr))
{
printf("pthread_attr_init() failure: %s\n", strerror(errno));
return -1;
}
//设置子线程与主线程为相分离的关系
if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED))
{
printf("pthread_attr_setdetachstate() failure: %s\n", strerror(errno));
return -1;
}
pthread_create(&tid, &thread_attr, thread_read, &sockfd);
while(1){
//数据写入套接字,发往服务端
memset(writeBuff,0,sizeof(writeBuff));
fgets(writeBuff,MAXSIZE,stdin);
write(sockfd,writeBuff,MAXSIZE);
}
close(sockfd);
}
void *thread_read(void *args)
{
int *sockfd = (int *)args;
char readBuff[MAXSIZE];
while(1){
//从套接字读入内存
memset(readBuff,0,sizeof(readBuff));
read(*sockfd,readBuff,MAXSIZE);
printf("Received string:[%s]\n",readBuff);
}
printf("thread_writeall exit\n");
return NULL;
}