1. 程式人生 > >linux下socket實現多個客戶端與伺服器的通訊

linux下socket實現多個客戶端與伺服器的通訊

學習完《UNIX環境高階程式設計》套接字一章的內容之後,自己實現了單個客戶端與伺服器的通訊程式,後面想想要是多個客戶端如何與伺服器通訊呢?這就有了這篇文章。

伺服器端程式:

#include<stdio.h>

#include <stdlib.h> 

#include <errno.h> 

#include <string.h> 

#include <netdb.h> 

#include <sys/types.h> 

#include <netinet/in.h> 

#include <sys/socket.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <fcntl.h>

#include <pthread.h>



#define BUFLEN 128

#define QLEN   10

#define DATALEN 200

#define SERVPORT 48800

#define HOST_NAME_MAX 256
#define IPLEN  16


//store accept id of client connect to server

int acceptfd[QLEN];
//number of client connect to server 

int acceptnum = 0;


//information from main thread to created thread 
struct threadinfo
{
	int 	clfd;
	char	ipaddr[IPLEN];
	int 	port;
};



void sys_err(char *errinfo)

{

	if(NULL == errinfo)

	{

		return;

	}

	perror("errinfo");

	exit(0);

}





int initsrver(int type, const struct sockaddr *addr, socklen_t alen, int qlen)

{

	int fd;

	int err = 0;

	int reuse = -1;



	if((fd = socket(addr->sa_family, type, 0)) < 0)

	{

		return -1;

	}
	//set socket option

	if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)) < 0)

		goto errout;



	if(bind(fd, addr, alen) < 0)

		goto errout;

	if(type == SOCK_STREAM || type == SOCK_SEQPACKET)

	{
		//listen

		if(listen(fd, qlen) < 0)

			goto errout;

	}



	return fd;



errout:

	err = errno;

	close(fd);

	errno = err;

	return -1;

}



void *recvmessage(void *arg)

{

	char buf[BUFLEN];

	char recvtitle[DATALEN] = "receive from ";

	int n;
	struct threadinfo *ti = arg;



	memset(buf, 0, BUFLEN);

	sprintf(recvtitle, "%s%s:%d ", recvtitle, ti->ipaddr, ti->port);

	while((n = recv(ti->clfd, buf, BUFLEN, 0)) > 0)

	{

		write(STDOUT_FILENO, recvtitle, strlen(recvtitle));

		write(STDOUT_FILENO, buf, n);

		memset(buf, 0, BUFLEN);

	}

	if(n < 0)

		printf("recv error\n");

}



void *acceptThread(void *sockfd)

{

	int clfd;

	const char *addr;



	char buf[BUFLEN];

	int n;

	char abuf[INET_ADDRSTRLEN];

	struct sockaddr_in clientsockaddr;

	int clientlen;

	int err;

	pthread_t recvtid;
	struct threadinfo ti;



	clientlen = sizeof(clientsockaddr);
	//always accept new client to accept a lot of client 

	while(1)

	{

		if((clfd = accept(*(int *)sockfd, (struct sockaddr *)&clientsockaddr, &clientlen)) < 0)

			sys_err("accept error");

		printf("%s:%d login in to server\n", inet_ntoa(clientsockaddr.sin_addr), clientsockaddr.sin_port);

		
		//when accept client, store it's accept id

		acceptfd[acceptnum++] = clfd;

		
		//create thread to receive message of every client
		ti.clfd = clfd;
		strcpy(ti.ipaddr, inet_ntoa(clientsockaddr.sin_addr));
		ti.port = clientsockaddr.sin_port;

		if((err = pthread_create(&recvtid, NULL, recvmessage, &ti)) != 0)

			sys_err("pthread_create recvmessage error");



	}

}



int communication(int sockfd)

{

	int 	clfd;

	pid_t	pid;

	char	buf[BUFLEN];



	int 	fd;

	int 	err;

	pthread_t acpttid;

	int 	i;



	memset(buf, 0, BUFLEN);


	//create thread to accept client, always accept to accept a lot of client

	if((err = pthread_create(&acpttid, NULL, acceptThread, &sockfd)) != 0)

		sys_err("pthread_create acceptThread error");


	//send message to client, but only send the same mesage to all connected client now

	memset(buf, 0, BUFLEN);

	while(1)

	{

		if(fgets(buf, BUFLEN, stdin) != NULL)

		{
			//print the num of accept client connect to server

			printf("acceptnum: %d\n", acceptnum);

			for (i = 0; i < acceptnum; ++i)

			{

				send(acceptfd[i], buf, strlen(buf), 0);

			}

			memset(buf, 0, BUFLEN);

		}

	}



	close(clfd);

}



int main(int argc, char *argv[])

{

	struct sockaddr_in serversockaddr, clientsockaddr;

	int 	sockfd, clientfd;

	int err, n;



	if(argc != 1)

	{

		printf("usage: %s\n", argv[0]);

		exit(0);

	}



	serversockaddr.sin_family = AF_INET;

	serversockaddr.sin_port = htons(SERVPORT);

	serversockaddr.sin_addr.s_addr = INADDR_ANY;

	bzero(&(serversockaddr.sin_zero), 8);



	if((sockfd = initsrver(SOCK_STREAM, (struct sockaddr *)&serversockaddr, sizeof(struct sockaddr), QLEN)) > 0)

	{
		//start communication

		communication(sockfd);

		exit(0);

	}



	exit(0);

}
客戶端程式:
#include<stdio.h>

#include <stdlib.h> 

#include <errno.h> 

#include <string.h> 

#include <netdb.h> 

#include <sys/types.h> 

#include <netinet/in.h> 

#include <sys/socket.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <fcntl.h>

#include <pthread.h>



#define SERVPORT 48800



#define MAXSLEEP 128

#define BUFLEN 128

#define DATALEN 200



int connect_retry(int domain, int type, int protocol, const struct sockaddr *addr)

{

	int numsec, fd;
	
	//try to connect with exponential backoff

	for(numsec = 1; numsec <= MAXSLEEP; numsec <<= 1)

	{

		if((fd = socket(domain, type, protocol)) < 0)

			return -1;



		if(connect(fd, addr, sizeof(struct sockaddr)) == 0)

		{

			return fd;

		}

		close(fd);


		//delay before trying again

		if(numsec <= MAXSLEEP/2)

			sleep(numsec);

	}

	return -1;

}



void *sendmessage(void *arg)

{

	int sockfd;

	char	buf[BUFLEN];



	sockfd = *(int *)arg;

	memset(buf, 0, BUFLEN);

	while(fgets(buf, BUFLEN, stdin) != NULL)

	{

		send(sockfd, buf, strlen(buf), 0);

		memset(buf, 0, BUFLEN);

	}

}



void communication(int sockfd)

{

	int n;

	pid_t pid;

	char buf[BUFLEN];



	char *recvtitle = "received from server: ";

	int fd;

	int err;

	pthread_t tid;



	memset(buf, 0, BUFLEN);

	
	//create thread to send message

	if(err = pthread_create(&tid, NULL, sendmessage, &sockfd))

	{

		printf("pthread_create error\n");

		exit(0);

	}


	//receive message

	while(1)

	{

		while((n = recv(sockfd, buf, BUFLEN, 0)) > 0)

		{

			write(STDOUT_FILENO, recvtitle, strlen(recvtitle));

			write(STDOUT_FILENO, buf, n);

			memset(buf, 0, BUFLEN);

		}

		if(n < 0)

			printf("recv error\n");

	}

}



int main(int argc, char *argv[])

{

	int sockfd, err;

	struct sockaddr_in serversockaddr;

	const char	*addr;

	char abuf[INET_ADDRSTRLEN];

	struct hostent *host;



	if(argc != 2)

	{

		printf("usage: %s hostname\n", argv[0]);

		exit(0);

	}



	if((host = gethostbyname(argv[1])) == NULL)

	{

		perror("gethostbyname");

		exit(0);

	}



	serversockaddr.sin_family = AF_INET;

	serversockaddr.sin_port = htons(SERVPORT);

	serversockaddr.sin_addr = *((struct in_addr *)host->h_addr);

	bzero(&(serversockaddr.sin_zero), 0);



	if((sockfd = connect_retry(serversockaddr.sin_family, SOCK_STREAM, 0, (struct sockaddr *)&serversockaddr)) < 0)

	{

		err = errno;

	}

	else

	{

		communication(sockfd);

		exit(0);

	}



	printf("can't connect to %s\n", argv[1]);

	exit(0);



}


相關推薦

linuxsocket實現客戶伺服器通訊

學習完《UNIX環境高階程式設計》套接字一章的內容之後,自己實現了單個客戶端與伺服器的通訊程式,後面想想要是多個客戶端如何與伺服器通訊呢?這就有了這篇文章。 伺服器端程式: #include<stdio.h> #include <stdlib.h&g

Java Socket客戶伺服器通訊

client程式碼: package com.cqut.test4; import java.io.*; import java.net.Socket; import java.net.SocketException; import java.net.U

linuxsocket程式設計 select實現非阻塞模式客戶伺服器通訊

select函式原型如下: int select (int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); select系統呼叫是用來讓我們的程式

Java Socket實現客戶連線同一個服務

使用Socket實現多個客戶端和同一客戶端通訊;首先客戶端連線服務端傳送一條訊息,服務端接收到訊息後進行處理,完成後再回復客戶端一條訊息。本人通過自己的思維編寫了一份服務端和客戶端實現的程式碼,望能與大家相互學習,共同進步。   服務端程式碼 /** * Socket服務

socket實現客戶連線在一個伺服器

1、使用socekt通訊一般步驟     1)伺服器端:socker()建立套接字,繫結(bind)並監聽(listen),用accept()等待客戶端連線。     2)客戶端:socker()建立套接字,連線(connect)伺服器,連線上後使用send()和recv(

LInux中利用執行緒實現客戶伺服器進行通訊

上一篇博文講了如何利用子程序實現多個客戶端和伺服器端進行通訊, 那麼,這一篇部落格就來實現一下如何利用執行緒實現多個客戶端和伺服器端進行通訊 程式碼實現: ser1.c #include <

使用線程實現客戶服務通信1

runnable system 處理異常 封裝 端口被占用 直接 客戶端連接 i++ 應用程序 Server.java package socket; import java.io.BufferedReader;import java.io.IOException;impo

java--實現客戶服務連線

在客戶端與服務端的簡單連線上進行了略微的新增,實現了多個客戶端與服務端的連線 目的: 多個客戶端與服務端的連線,實現服務端發訊息客戶端可以接受到 程式碼: 服務端 import java.io.IOE

Linux c==TCP的客戶連線伺服器 (20)

通過父子程序實現TCP的多個客戶端連線伺服器 tcp_sever_fork.c #include <stdio.h> #include <string.h> #i

select實現客戶伺服器之間的通訊

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <assert.h> #include <sys/select.h> #incl

tcp 路複用實現客戶之間的通訊

/******************************* 伺服器端  ****************************/ #include <stdio.h> #include <stdlib.h> #include <neti

SOCKET讀取客戶下面基站下面手環傳送的資料(驗收專案版本)

之前,本人,發了一大堆關於socket 多執行緒 客戶端 的一大堆博文,有理論的也有實現版本的,有缺陷有成功的! 但是,今天我要說的是,之前的關於socket博文的,都有誤區,而且達不上真正驗收專案的標準!! 今天是2018/10/7 17:09:00,我真正實現了這個功

linux如何實現定時器

最近在linux下寫一個庫,是給別人用的,要用到定時器這個功能,而且是多定時器任務的,在windows下實現是很方便的,但是 在linux下就遇到了問題,linux下一個程序只能有一個定時器,如果我用了定時器去實現我的任務,那肯定是沒問題的,如果用我庫的人自己也建立了一個定

socket 存在客戶時,一對一連線

1、連線的客戶端實體類package com.example.demo.socket3; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader;

Unity中的Socket通訊客戶的非同步通訊

using UnityEngine; using System; using System.Net; using System.Net.Sockets; using System.Collections; using System.Text; using System.Collections.Generic;

(二)用執行緒管理TCP客戶連線伺服器

該程式的服務端大概工作邏輯如左圖: 首先說說這個程式的作用:這個程式可用於多個客戶端通過連線伺服器來互相通訊。如qq群聊。當一個客戶端有資訊發過來後,服務端就會通過客戶端佇列轉發給其他客戶端 先上程式碼: //TCP服務端 #include"myhead.h" struc

客戶之間的通訊

伺服器 #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/socket.h> #include &

java_執行緒_socket通訊_客戶傳送,伺服器響應

/** * 伺服器端不斷接受請求 * 接受一個請求開啟一段執行緒 */ package 練習0927; import java.io.BufferedReader; import java.io.IOException; import java.io.InputSt

五、通過Protobuf整合Netty實現對協議訊息客戶伺服器通訊實戰

目錄 一、Protocol Buffers 是什麼? 二、Protocol Buffers 檔案和訊息詳解 三、專案實戰,直接掌握的protobuf應用。 一、Protocol Buffers 是什麼?         1、官網翻譯