700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > linux 多线程客户端服务端通信 [转载]多线程实现服务器和客户端 客户端和客户端通

linux 多线程客户端服务端通信 [转载]多线程实现服务器和客户端 客户端和客户端通

时间:2024-07-20 10:23:41

相关推荐

linux 多线程客户端服务端通信 [转载]多线程实现服务器和客户端 客户端和客户端通

一、实验名称

动手打造自己的IM

二、实验目的

1本次实验旨在锻炼大家的Socket编程能力,以日常生活中广泛使用的IM软件为背景,培养大家对于网络编程的兴趣。

2、通过本次实验,培养linux环境下网络编程能力,使得我们对网络应用层的网络应用软件有了一个深入的理解,这对网络课程的学习起到了很好的实践作用。

三、实验内容及步骤

实验内容:本作业要求同学们完成一个简陋的IM的客户端和服务器端,实现一些最基本和最常用的IM功能:

客户端功能:

1、4个以!开头命令,!login登录命令!list列出在线用户命令!file传输文件命令!logoff注销命令。

2、回显功能:当其他用户登录或者登出时,客户端会收到服务器的提示信息,当向另一个客户端发送文件之后,也会收到该客户端的提示信息。

3、聊天功能:两个客户端可以进行聊天:

以[username]:开头的行为其他用户向你发送的聊天信息。

以>>[username]:开头的行为你向其他用户发送的聊天信息。

服务器功能:

Server端基本架构:多进程并发服务器实现,为每个在线用户分配一个进程用以和在线用户保持通信,并在子进程退出(某用户下线)时,回收子进程资源。

ü服务器端固定端口:8081

ü用户登录成功,反馈提示信息

ü维护在线用户信息:包括IP地址和端口号,用户名字,用户密码等

ü向在线用户发出其他用户上/下线提示信息

实验步骤:

1、熟悉Linux下C语言的编程环境和编译方法,学会用gedit来编写并修改代码及命令行工具。

2、学习有关socket方面的有关知识,尝试着去编写服务器端和客户端的实现连接的代码,最重要的是学会使用socket()、listen()、bind()、connect()、accept()等函数的使用方法,在此基础上实现客户端和服务器端的连接。

3、在实现客户端和服务器端连接的基础上编写处理!login、!logoff、!list等简单的命令(无需客户端与客户端交互),这个过程最重要的是学会send()、recv()函数的使用,传递套接字时要注意接收和发送的对应。

4、在实现了单个客户端与服务器的用简单命令交互的基础上,学习线程的有关知识在服务器端创建多线程,实现服务器可以和多个客户端交互的功能。此过程最重要的是学会线程创建和使用,最重要的是pthread_create(4个参数)的使用,其中关键的地方是线程函数的建立及其参数的传递,参数是socket,这样才能在线程中实现与客户端的交互。

5、在实现了多个客户端与服务器进行交互的基础上,就有可能实现客户端与客户端的交互,编程时一个很关键的地方就是所使用的数据结构,没有一个存储logined客户端的数据结构,就很难实现客户端与客户端的交互。因此需要建立一个结构体来存储客户端的socket、port(可选)、username、flag(状态)。

两种方案:

1)从服务器获得另一个客户端的端口号和IP后,让客户端与客户端建立连接,实现直接交互,这就是P2P结构,编程时我试着使用了这种方法,但是连接总是出问题。

2)通过服务器实现客户端之间的交互,简单来说就是客户端把信息通过socket发送到服务器,服务器再把信息通过不同的socket发送到客户端,这是建立在每个客户端都有自己的socket的基础上的。

我选择了第二种方案来实现客户端的交互。

6、编程进行到这里,我突然意识到了如果客户端没有监听服务器的代码,无法接收和识别服务器的信息是客户端要发送的信息、还是服务其本身要发送的信息,思考良久,无奈之下只能大篇幅的修改代码,在客户端使用双线程,一个用于监听键盘的输入,一个用于监听服务器是否发送信息;这样当键盘输入时一个线程接收并负责向服务器发送信息,当收到服务器发送的信息时,另一个线程接收并把信息输出到终端上。

7、在以上的基础上,就可以实现客户端的通话及文件的发送,最后就是调试程序并整理输出的格式。

四、实验分析

1,server.c编译及运行结果:

图1处于监听状态的服务器

2,开启另外终端运行客户端程序:

第一个用户:Me,运行客户端程序之后,使用命令!login登录,成功登录后会收到服务器的发送的信息,结果如下:

图2一个client登陆成功后的服务器

图3第一个客户端Me登陆成功

另起两个终端第二个客户端You和第三个客户端Him登录后结果如下:

图4多个客户端登陆后的服务器

3,指令!list的使用:

图5Me客户端上执行!list命令

4,!logoff命令:当用户Me执行!logoff后,客户端显示服务器发送的信息,此时使用!list指令,结果如下:

图6客户端Him执行!logoff命令

图7客户端Him执行!logoff命令后Me执行!list的结果

5,聊天功能演示:

图8Me客户端和You客户端进行通话

图9You客户端和Me客户端通话

6,指令!file的使用,文件传输功能演示:

图10You客户端向Me发送lilufeng.pdf文件显示成功

图11Me客户端接收文件成功信息

7、几种错误处理,结果如下:

图12用户名错误登录失败

图13发送文件时用户不在线、发送失败

图14Me想和You对话,You没有登录,连接失败

五、实验结论

难点:

1、本实验是基于Linux环境下,使用C语言编写而成,这两者都需要实验前进行深入的探索和学习,对我而言,加大了编程和实现的难度。

2、对socket和thread方面的知识可以说一无所知,编程的过程中要不断地学习才能向前迈一小步。

感受:

1、这次实验的过程中,我深知自己的知识的匮乏,实验的过程可以说完全是一个探索的过程,对用到的函数我必须要在Dev等工具下先进性一定的应用和学习才能真正掌握其用法和内涵,实践的过程中学到了很多的知识,而且在编程的后面阶段感觉对这些知识已经能够熟练地应用,最有说服力的就是那些函数的掌握,可见,软件这个行业只有在实践中才能真正的学到本领。

2、编程的前后,我的代码被改了很多遍,因为开始编程的时候没有一个整体的构思,只能走一步算一步,每走一步都是那么的艰难,线程的加入和数据结构的改变都使原来的代码结构发生天翻地覆的变化,到最后在客户端加入双线程时整体的代码又改了一遍,所以说这次试验让我感觉非常的累,而且过程中感觉网络编程是那么的复杂,现在想想这些东西,还是很简单的。由此,我明白了开发软件前为什么要进行详细的设计,看着是浪费时间,其实那是在节省时间和精力,而且是开发出一个软件的基础。

3、通过这次试验让我学会了关于网络的socket和P2P等很多知识,这些知识在短期或者说今生难于忘记,当然还有操作系统方面的thread和process方面的知识。

4、同时我也感受到了IT人士的辛劳,其实我一直都在感受到,只不过这次更加强烈罢了,不过辛劳后,看到自己的成果和感到内心的充实,觉得付出还是值得的。

客户端程序源码:

//[浠g爜]

tcpclient.c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define

SERVER_PORT 8081 //

define the defualt connect port

id

#define

BUFFER_SIZE 255 //buf size

int

clifd,length = 0;//socket size

char

buf[BUFFER_SIZE]; //the buffer of socket

pthread_t

thread;//thread discription

char

command[100],uName[20],pwd[20];

void

*listenServer(int);//listen and receive message from the server

int

cli_socket_connect_server(int);//create socket and connect the

server

int

main(int argc)

{

clifd =

cli_socket_connect_server(SERVER_PORT);//return the socket

while(1)

{ char

frontcmd[20],ch1,ch2;

int countcmd

=0,countFcmd=0;

memset(frontcmd,' ',sizeof(frontcmd));

memset(command,' ',sizeof(command));

memset(buf,' ',sizeof(buf));

while(ch1 =

getchar()) //input the command

{

if(ch1 == ' ')

{

while(ch2 =

getchar())

{

if(ch2 == 'n')

break;

else

command[countcmd++]

= ch2;

}

break;

}

else if(ch1 ==

'n')

break;

else

frontcmd[countFcmd++] = ch1;

}//input

over:frontcmd is the really command

if(frontcmd[0] ==

'>')//talk function process

{

strcpy(buf,">>");

send(clifd,buf,BUFFER_SIZE,0);

char *talkto;

talkto =

strtok(frontcmd,">:");

strcpy(buf,talkto);//talk to whom

strcat(buf,":");//:

is used to strtok in the server

strcat(buf,command);//what you send

send(clifd,buf,BUFFER_SIZE,0);

}

if(strcmp(frontcmd,"!logoff") == 0)//logoff command process

{

strcpy(buf,"!logoff");

send(clifd,buf,BUFFER_SIZE, 0);

strcpy(buf,uName);

send(clifd,buf,BUFFER_SIZE, 0 );

close(clifd);

pthread_exit(NULL);

break;

}//end of logoff

if

if(strcmp(frontcmd,"!list") == 0)//list command process

{

strcpy(buf,"!list");

send(clifd,buf,BUFFER_SIZE, 0 );

}//end of list

if

if(strcmp(frontcmd,"!login") == 0)//login command process

{

strcpy(buf,"!login");

send(clifd,buf,BUFFER_SIZE, 0 );

printf("User

name:t");

scanf("%s",uName);

printf("Password:t");

scanf("%s",pwd);

strcpy(buf,uName);

send(clifd,buf,BUFFER_SIZE, 0 );

length =

recv(clifd,buf,BUFFER_SIZE,0);

if

(length < 0)

{

printf(" error comes

when recieve data from server! send filen");

exit( 1 );

}

printf("From

server:nt%sn",buf);

if(pthread_create(&thread, NULL, (void

*)listenServer, (void *)clifd) == 0) //after login success create

the listenServer thread

{

printf("listen

thread create success!n");

}

else

{

printf("listen

thread create failed!n");

exit(1);

}

}//end of login

if

if(strcmp(frontcmd,"!file") == 0)

{

strcpy(buf,frontcmd);//send front command(!file) to the server

send(clifd,buf,BUFFER_SIZE,0);

char

*file,*toUser;

file =

strtok(command," =>");//file

toUser =

strtok(NULL," =>");//destination user

printf("filename:t%sntoUser:t%s",file,toUser);

strcpy(buf,toUser);//send the file to whom

send(clifd,buf,BUFFER_SIZE,0);

}//end of file

if

}//end of while

return 0;

}

void

*listenServer(int file_socket)

{

while(recv(file_socket,buf,BUFFER_SIZE,0)>0)

{

char *flagcmd =

NULL,*printInfo = NULL;

flagcmd =

strtok(buf,"|");

printInfo =

strtok(NULL,"|");

if(strcmp(flagcmd,"!list") == 0)//list the user that logined

now

printf("from

server:n%s",printInfo);

else

if(strcmp(flagcmd,"!logoff") == 0)//logoff

printf("from

server:nt%s",printInfo);

else

if(strcmp(flagcmd,"!file") == 0)//send the file

{

if(strcmp(printInfo,"0") == 0)//destination user does not login

printf("From

server:ntuser does not login,file failed!n");

else

//destination user logined

printf("nConnect

success!file success!n");

}

else

if(strcmp(flagcmd,"!msg") == 0)//receive the file message

{

printf("From

sever:nt%s",printInfo);

}

else

if(strcmp(flagcmd,"!talk") == 0)//talk message

{

if(strcmp(printInfo,"0") == 0)

printf("The user

does not login!n");

else

printf("%sn",printInfo);

}

else

printf("Please

debug!");

}

}

int

cli_socket_connect_server(int serverPort)

{

struct

sockaddr_in cliaddr;

socklen_t socklen

= sizeof(cliaddr);

char

sever[20];//store the IP

int

client_socket;

if((client_socket

= socket(AF_INET,SOCK_STREAM, 0

)) < 0

)//create socket of the client

{

printf(" create

socket error!n ");

exit( 1 );

}

bzero(

& cliaddr,sizeof(cliaddr));

cliaddr.sin_family

= AF_INET;

inet_aton(sever,

& cliaddr.sin_addr);

cliaddr.sin_port

= htons(serverPort);//port of

the sever

cliaddr.sin_addr.s_addr =

htons(INADDR_ANY);//the same IP with the

sever.Connect auto!

if(connect(client_socket,(struct sockaddr * )

& cliaddr, socklen)

< 0 )//connect

the server

{

printf(" can't

connect!n ");

exit( 1 );

}

return

client_socket; //return the socket

}

服务器端源码:

//tcpserver.c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define

SERVER_PORT 8081 //

define the defualt connect port

id

#define

LENGTH_OF_LISTEN_QUEUE 10 //

length of listen queue in server

#define

MAX_THREAD 10

#define

BUFFER_SIZE 255

#define

SUCCESS_MESSAGE "Login

Success!"

#define

FAIL_MESSAGE "Login Failed!"

#define

TOTAL_USER_NUM 6

struct

clientInformation

{

int flag;

//record

the struct state: 0 is empty

char loginUsr[20];

//the users that have logined

int socket;

//store the logined uses'

socket

};

struct

clientInformation clientInfo[TOTAL_USER_NUM];//logined users'

array

int

servfd,sever_socket; //the socket

int len=0;

//record the length of the socket

int numOfThread = 0;

//record the number of

threads

char users[6][10] =

{"Me","You","Him","Her","user","tmd"};//users that can login

char

buf[BUFFER_SIZE]; //the capacity of the

socket

pthread_t

thread[MAX_THREAD]; //thread discription

struct

sockaddr_in servaddr,cliaddr;

void*

docommand(int);//thread function

int main(int

argc)

{

int num;

for(num = 0; num

< TOTAL_USER_NUM; num++)

{

clientInfo[num].flag

= 0;

clientInfo[num].socket = 0;

}

if ((servfd =

socket(AF_INET,SOCK_STREAM, 0 ))

< 0 )//create

socket in the server

{

printf(" create socket

error!n ");

exit( 1

);

}

bzero( &

servaddr,sizeof(servaddr));

servaddr.sin_family =

AF_INET;

servaddr.sin_port =

htons(SERVER_PORT);

servaddr.sin_addr.s_addr =

htons(INADDR_ANY);

if(bind(servfd,(struct sockaddr

* ) & servaddr,sizeof(servaddr)) < 0

)//bind

{

printf(" bind to

port %d failure!n ",SERVER_PORT);

exit( 1

);

}

if(listen(servfd,LENGTH_OF_LISTEN_QUEUE)

< 0

)//listen

{

printf("

call listen failure!n ");

exit( 1

);

}

while(numOfThread

< MAX_THREAD)

{

socklen_t length

= sizeof(cliaddr);

sever_socket =

accept(servfd,(struct sockaddr

* ) & cliaddr, & length);//accept

the login

if

(sever_socket <

0 )

{

printf("

error comes when call accept!n ");

break;

}

else

{

//void* arg[] =

{&sever_socket};

if(pthread_create(&thread[numOfThread++], NULL,

(void *)docommand, (void *)sever_socket) != 0)

printf("绾跨▼%d鍒涘缓澶辫触!n",numOfThread); //create

the new thread to the login client

else

printf("绾跨▼%d琚垱寤簄",numOfThread);

}

}

close(servfd);

return 0

;

}

void *docommand(int

sever_socket)

{

while

( 1 )

{// server loop will nerver exit unless any body kill the process

memset(buf,' ',sizeof(buf));

len

= recv(sever_socket, buf,

BUFFER_SIZE, 0); //recv the

command

if

(len < 0)

{

printf(" error comes when

recieve data from client ! " );

exit( 1 );

}

else

{

if(strcmp(buf,">>") == 0) //talk

process

{

len

= recv(sever_socket, buf,

BUFFER_SIZE, 0);//recv the user name that the file will be sent

to

if

(len < 0)

{

printf("error comes when

recieve data from client ! " );

exit( 1 );

}

char

temp[100],*talkto;

strcpy(temp,buf);//temp store what will be sent

talkto =

strtok(buf,":");

int j;

for(j = 0;j

< TOTAL_USER_NUM;j++)

{

if(clientInfo[j].flag == 1)

{

if(strcmp(clientInfo[j].loginUsr,talkto) == 0)

{

strcpy(buf,"!talk|");

strcat(buf,temp);//move temp(the information) to buf

send(clientInfo[j].socket,buf,BUFFER_SIZE,0);//send the talking

message to whom what you talk

break;

}

}

}

if(j ==

TOTAL_USER_NUM)

{

strcpy(buf,"!talk");

strcat(buf,"|0");//"0" == user does not login

send(sever_socket,buf,BUFFER_SIZE, 0 ); //send message(user does

not login)

}

}

else

if(strcmp(buf,"!file") == 0) //file process

{

len

= recv(sever_socket, buf,

BUFFER_SIZE, 0);//recv the user name that the file will be sent

to

if

(len < 0)

{

printf("error comes when

recieve data from client ! " );

exit( 1 );

}

int i;

for(i = 0;i

< TOTAL_USER_NUM;i++)

{

if(clientInfo[i].flag == 1)

{

if(strcmp(clientInfo[i].loginUsr,buf) == 0)

{

strcpy(buf,"!file|");

strcat(buf,"1");//"1" == user logined

send(sever_socket,buf,BUFFER_SIZE, 0 ); //send to the client who

send file(receiver)

strcpy(buf,"!msg|nreceived the file!n");

send(clientInfo[i].socket,buf,BUFFER_SIZE,0);//tell the client to

recv the file

break;

}

}

}

if(i ==

TOTAL_USER_NUM)

{

strcpy(buf,"!file");

strcat(buf,"|0");//"0" == user does not login

send(sever_socket,buf,BUFFER_SIZE, 0 ); //send message(user does

not login)

}

}//end of if

else

if(strcmp(buf,"!list") == 0) //list the logined users process

{

strcat(buf,"|");

int k;

for(k = 0; k

< TOTAL_USER_NUM; k++)

{

if(clientInfo[k].flag == 1)

{

strcat(buf,clientInfo[k].loginUsr);

strcat(buf,"n");

}

}

send(sever_socket,buf,BUFFER_SIZE,0); //send all logined users to

client

}//end of else if

1

else

if(strcmp(buf,"!logoff") == 0) // logoff process

{

while(1)

{

strcat(buf,"|logoff

success!n");

send(sever_socket,buf,BUFFER_SIZE,0); //send logoff success

message

memset(buf,' ',sizeof(buf));

len

= recv(sever_socket, buf,

BUFFER_SIZE, 0); //recv the login users name

int k;

for(k = 0; k

< TOTAL_USER_NUM; k++)//move it out from the

clientinformation struct

{

if(strcmp(buf,clientInfo[k].loginUsr) == 0)

{

strcpy(clientInfo[k].loginUsr," ");

clientInfo[k].flag =

0;

clientInfo[k].socket

= 0;

break;

}

}

close(sever_socket);

numOfThread--;

pthread_exit(NULL);

break;

}

}//end of else if

2

else

if(strcmp(buf,"!login") == 0)//login process

{

len

= recv(sever_socket, buf,

BUFFER_SIZE, 0); //recv the login user's name

if

(len < 0)

{

printf("error comes when

recieve data from client ! login" );

exit( 1 );

}

printf("from

client:%stIP:%stPort:%dn ",buf,

inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port));

int i;

for(i = 0;i

< TOTAL_USER_NUM;i++)//judge whether have this

user

{

if(strcmp(buf,users[i]) == 0)

{

for(i = 0;i

< TOTAL_USER_NUM;i++)

{

if(clientInfo[i].flag == 0)

{

strcpy(clientInfo[i].loginUsr,buf);

clientInfo[i].socket

= sever_socket;

clientInfo[i].flag =

1;

break;

}

}

strcpy(buf,SUCCESS_MESSAGE);

send(sever_socket,buf,BUFFER_SIZE, 0 ); //send login success

message

break;

}

}

if(i ==

TOTAL_USER_NUM)

{

printf("No user

called %s! Login failed!n",buf);

memset(buf,' ',sizeof(buf));

strcpy(buf,FAIL_MESSAGE);

send(sever_socket,buf,BUFFER_SIZE, 0 ); //send login failed

message

}

}//end of else if

3

} //end of else

}// end of while

}

又不懂得地方,欢迎留言询问,我必尽力解答!

linux 多线程客户端服务端通信 [转载]多线程实现服务器和客户端 客户端和客户端通信;需要代码 留言...

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。