文档库 最新最全的文档下载
当前位置:文档库 › 基于Linux的socket编程模板

基于Linux的socket编程模板

基于Linux的socket编程模板
基于Linux的socket编程模板

基于Linux的socket编程模板

在网络编程编程中,我们经常会遇到这样一种C/S架构,服务器端(Server)监听客户端(Client)发送过来的命令,然后解析该命令,并做对应的处理,最后返回处理结果(例如成功或者失败及原因)给客户端。

最近,在Linux下做网络编程,涉及的就是上面的这种需求,简单地整理了下自己的代码,分享在这里吧,供初学者参考。

首先说一下编程思路吧。

在这种情况客户端必须实现的的接口有:连接服务器、发送、断开连接。

服务器端,有一个主线程,用于监听客户端的连接请求,一旦有新客户端连接,则创建一个新的socket及线程专门服务这个客户端。这个服务线程专门监听该客户端的命令,并且解析命令进行服务器,直到客户端断开连接或者发送关闭连接的命令。

另外,需要涉及一个通信协议,约定命令的包头、命令的识别码、命令的参数。

思路就说到这儿了,下面的相关代码,附件中有完整的代码,包含了Makefile文件。

一、通信协议设计

1.////////////////////////////////////////////////////////////////////////

//

2.// COPYRIGHT NOTICE

3.// Copyright (c) 2011, 华中科技大学 ticktick(版权声明)

4.// All rights reserved.

5.//

6./// @file Command.h

7./// @brief 命令包声明文件

8.///

9./// 定义各种TCP命令包以及相关结构体

10.///

11./// @version 1.0

12./// @author lujun

13./// @E-mail lujun.hust@https://www.wendangku.net/doc/5411525006.html,

14./// @date 2011/08/21

15.//

16.//

17.// 修订说明:

18.////////////////////////////////////////////////////////////////////////

//

19.

20.#ifndef COMMAND_H_

21.#define COMMAND_H_

22.

23.typedef unsigned char uint8_t;

24.

25.// TCP CMD header len

26.#define TCP_CMD_HEADER_LEN 8

27.

28.// CMD header

29.static uint8_t TCP_CMD_HEADER_STR[TCP_CMD_HEADER_LEN] = { 0xAA,0xA1,0xA2

,0xA3,0xA4,0xA5,0xA6,0xFF };

30.

31.// max user name len

32.#define MAX_USER_NAME_LEN 20

33.

34.// server cmd struct

35.typedef enum _ServerCMD

36.{

37. CMD_SAVE_USER_NAME, // save user name

38. CMD_SAVE_USER_AGE, // save user age

39.

40.}ServerCMD;

41.

42.// return cmd

43.typedef enum _ReturnCMD

44.{

45. DVS_RETURN_SUCCESS = 0,

46. DVS_RETURN_FAIL,

47. DVS_RETURN_TIMEOUT,

48. DVS_RETURN_INVLID_HEADER,

49. DVS_RETURN_INVLID_CMD,

50. DVS_RETURN_INVLID_PRM,

51.

52.}ReturnCMD;

53.

54.// 1bytes aligning

55.#pragma pack( push, 1 )

56.

57.// server pack from client

58.typedef struct _ServerPack

59.{

60.// cmd header

61. uint8_t cmdHeader[TCP_CMD_HEADER_LEN];

62.

63.// command id

64. ServerCMD serverCMD;

65.

66.// cmd param

67.union

68. {

69.// save user name

70.struct

71. {

72.// user name

73.char username[MAX_USER_NAME_LEN];

74.

75. }UserName;

76.

77.// save user age

78.struct

79. {

80.// user age

81.int userage;

82.

83. }UserAge;

84.

85. }Parameters;

86.

87.}ServerPack;

88.

89.// return pack from server

90.typedef struct _ReturnPack

91.{

92.// cmd header

93. uint8_t cmdHeader[TCP_CMD_HEADER_LEN];

94.

95.// return cmd

96. ReturnCMD returnCMD;

97.

98.}ReturnPack;

99.

100.#pragma pack( pop )

101.

102.#define SERVER_PACK_LEN sizeof(ServerPack)

103.#define RETURN_PACK_LEN sizeof(ReturnPack)

104.

105.#endif // COMMAND_H_

二、客户端代码

1.////////////////////////////////////////////////////////////////////////

//

2.// COPYRIGHT NOTICE

3.// Copyright (c) 2011, 华中科技大学 ticktick(版权声明)

4.// All rights reserved.

5.//

6./// @file client.c

7./// @brief tcp客户端代码

8.///

9./// 实现tcp客户端的相关接口

10.///

11./// @version 1.0

12./// @author lujun

13./// @E-mail lujun.hust@https://www.wendangku.net/doc/5411525006.html,

14./// @date 2011/08/21

15.//

16.//

17.// 修订说明:

18.////////////////////////////////////////////////////////////////////////

//

19.

20.#include

21.#include

22.#include

23.#include

24.#include

25.#include

26.#include

27.#include "client.h"

28.

29.// socket handle

30.int g_hSocket;

31.

32.int connect_server( char *destIp, int destPort )

33.{

34.int result;

35.struct sockaddr_in address;

36.

37.// create a socket

38. g_hSocket = socket(AF_INET,SOCK_STREAM,0);

39.

40.// set server addr

41. address.sin_family = AF_INET;

42.

43.// use server ip and listen port to connect

44. address.sin_addr.s_addr = inet_addr( destIp );

45. address.sin_port = htons(destPort);

46.

47.// connect tcp server

48. result = connect(g_hSocket,(struct sockaddr *)&address,sizeof(addres

s) );

49.if( result == -1 )

50. {

51. printf("[tcp client] can't connect server !\n");

52.return -1;

53. }

54.

55.return 0;

56.}

57.

58.int close_connect()

59.{

60. printf("close connect with server !\n ");

61.

62. close(g_hSocket);

63.

64.return 0;

65.}

66.

67.int send_cmd( ServerPack sPack )

68.{

69.int recvBytes = 0;

70.int sendBytes = 0;

71. ReturnPack rPack;

72.

73.// add cmd header

74. memcpy(sPack.cmdHeader,TCP_CMD_HEADER_STR,TCP_CMD_HEADER_LEN);

75.

76.// send cmd

77.while(1)

78. {

79. sendBytes = send(g_hSocket,(uint8_t *)&sPack,SERVER_PACK_LEN,0);

80.

81.if( sendBytes == SERVER_PACK_LEN )

82. {

83. printf("successfully send bytes %d\n",SERVER_PACK_LEN);

84.break;

85. }

86.else if( sendBytes <= 0 && errno != EINTR && errno != EWOULDBLOC

K && errno != EAGAIN)

87. {

88. printf("disconnected or other errors!\n");

89.return -1;

90. }

91.else

92. {

93.continue;

94. }

95. }

96.

97.// recv process result from server

98.while(1)

99. {

100. recvBytes = recv(g_hSocket,(uint8_t *)&rPack,RETURN_PACK_LEN ,0);

101.

102.if( recvBytes == RETURN_PACK_LEN )

103. {

104.break;

105. }

106.else if( recvBytes <=0 && errno != EINTR && errno != EWOUL DBLOCK && errno != EAGAIN )

107. {

108. printf("disconnected or error occur!\n close the socke t!\n");

109.return -1;

110. }

111.else

112. {

113.continue;

114. }

115. }

116.

117.// check header

118.if ( memcmp( rPack.cmdHeader, TCP_CMD_HEADER_STR, TCP_CMD_HEADER _LEN ) != 0 )

119. {

120. printf("return pack header errror!\n");

121.return -2;

122. }

123.

124.// get return status

125.if( rPack.returnCMD != DVS_RETURN_SUCCESS )

126. {

127. printf("return status : fail!\n");

128.return -3;

129. }

130.

131.return 0;

132.}

133.

134.

三、服务器主线程代码

1.////////////////////////////////////////////////////////////////////////

//

2.// COPYRIGHT NOTICE

3.// Copyright (c) 2011, 华中科技大学 ticktick(版权声明)

4.// All rights reserved.

5.//

6./// @file server.c

7./// @brief tcp服务器主线程代码

8.///

9./// 实现tcp服务端监听线程相关函数

10.///

11./// @version 1.0

12./// @author lujun

13./// @E-mail lujun.hust@https://www.wendangku.net/doc/5411525006.html,

14./// @date 2011/08/21

15.//

16.//

17.// 修订说明:

18.////////////////////////////////////////////////////////////////////////

//

19.

20.#include

21.#include

22.#include

23.

24.#include

25.#include

26.

27.#include "serverIf.h"

28.

29.int g_hServerSocket;

30.

31.int open_port( int localport )

32.{

33.int result;

34.int clientSocket,client_len;

35.

36.struct sockaddr_in server_addr;

37.struct sockaddr_in client_addr;

38.

39.// create a socket obj for server

40. g_hServerSocket = socket(AF_INET,SOCK_STREAM,0);

41.

42.// bind tcp port

43. server_addr.sin_family = AF_INET;

44. server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

45. server_addr.sin_port = htons(localport);

46.

47. result = bind(g_hServerSocket,(struct sockaddr *)&server_addr,sizeof

(server_addr) );

48.if( result != 0 )

49. {

50. printf("[tcp server] bind error!\n ");

51.return -1;

52. }

53.

54.// begin to listen

55. result = listen(g_hServerSocket,5);

56.if( result != 0 )

57. {

58. printf("[tcp server] listen error!\n ");

59.return -1;

60. }

61.

62. // 注: ServerEnv用于给服务线程传参,定义于serverIf.h中

63. ServerEnv env;

64.while(1)

65. {

66. client_len = sizeof(client_addr);

67. clientSocket = accept(g_hServerSocket,(struct sockaddr *)&clie

nt_addr,&client_len );

68.

69.if( clientSocket < 0 )

70. {

71. printf("[tcp server] accept error!\n" );

72.return -1;

73. }

74.

75. env.m_hSocket = clientSocket;

76.

77.// add new tcp server thread

78. add_new_tcp_process_thr(&env);

79. }

80.

81.return 0;

82.}

83.

84.int close_port()

85.{

86. printf("close server port, stop listen!\n");

87.

88. close(g_hServerSocket);

89.

90.return 0;

91.}

四、服务器端服务线程代码

1.////////////////////////////////////////////////////////////////////////

//

2.// COPYRIGHT NOTICE

3.// Copyright (c) 2011, 华中科技大学 ticktick(版权声明)

4.// All rights reserved.

5.//

6./// @file serverIf.c

7./// @brief tcp服务线程代码

8.///

9./// 实现tcp服务线程相关接口

10.///

11./// @version 1.0

12./// @author lujun

13./// @E-mail lujun.hust@https://www.wendangku.net/doc/5411525006.html,

14./// @date 2011/08/21

15.//

16.//

17.// 修订说明:

18.////////////////////////////////////////////////////////////////////////

//

19.

20.#include "serverIf.h"

21.#include "../include/Command.h"

22.#include

23.#include

24.#include

25.#include

26.

27.int add_new_tcp_process_thr( ServerEnv *envp )

28.{

29. pthread_t tcpThr;

30.

31.if( pthread_create( &tcpThr,NULL,tcpServerThrFxn,envp ) )

32. {

33. printf("tcp thread create fail!\n");

34.return -1;

35. }

36.

37. printf("tcp thread has been created!\n");

38.

39.return 0;

40.}

41.

42.int save_user_name( char * pUsername )

43.{

44. printf("ok,user name saved,username=%s\n",pUsername);

45.

46.return 0;

47.}

48.

49.int save_user_age( int age )

50.{

51. printf("ok,user age saved,userage=%d\n",age);

52.

53.return 0;

54.}

55.

56.void * tcpServerThrFxn( void * arg )

57.{

58. ServerEnv * envp = (ServerEnv *)arg;

59.int socketfd = envp->m_hSocket;

60.int returnBytes;

61.

62. ServerPack sPack;

63. ReturnPack rPack;

64. memcpy(rPack.cmdHeader,TCP_CMD_HEADER_STR,TCP_CMD_HEADER_LEN);

65.

66.while(1)

67. {

68.// read cmd from client

69. returnBytes = recv(socketfd,(uint8_t *)&sPack,SERVER_PACK_LEN,

0);

70.if( returnBytes == SERVER_PACK_LEN )

71. {

72.//printf("ok,recv %d bytes! \n",SERVER_PACK_LEN);

73. }

74.else if( returnBytes <= 0 && errno != EINTR && errno != EWOULD

BLOCK && errno != EAGAIN )

75. {

76. printf("disconnected or error occur! errno=%d\n ",errno);

77.break;

78. }

79.else

80. {

81.continue;

82. }

83.

84.// check the header

85.if ( memcmp( sPack.cmdHeader, TCP_CMD_HEADER_STR, TCP_CMD_HEAD

ER_LEN ) != 0 )

86. {

87. rPack.returnCMD = DVS_RETURN_INVLID_HEADER;

88.

89.// return error info to client

90. returnBytes = send(socketfd,(uint8_t *)&rPack,RETURN_PACK_

LEN,0 ) ;

91.if( returnBytes < RETURN_PACK_LEN)

92. {

93. printf("send error!\n");

94.continue;

95. }

96. }

97.

98.// analyse cmd

99. rPack.returnCMD = DVS_RETURN_SUCCESS;

100.switch( sPack.serverCMD )

101. {

102.case CMD_SAVE_USER_NAME:

103. {

104.if( save_user_name(https://www.wendangku.net/doc/5411525006.html, ername) != 0)

105. {

106. rPack.returnCMD = DVS_RETURN_FAIL;

107. }

108. }

109.break;

110.case CMD_SAVE_USER_AGE:

111. {

112.if( save_user_age(https://www.wendangku.net/doc/5411525006.html,erag

e) != 0)

113. {

114. rPack.returnCMD = DVS_RETURN_FAIL;

115. }

116. }

117.break;

118.default:

119. {

120. rPack.returnCMD = DVS_RETURN_INVLID_CMD;

121. }

122.break;

123. }

124.

125.// return result info to client

126. returnBytes = send(socketfd,(uint8_t *)&rPack,RETURN_PACK_ LEN,0 );

127.if( returnBytes < RETURN_PACK_LEN )

128. {

129. printf("send error!\n");

130.continue;

131. }

132. }

133.

134. printf("close session socket!");

135.

136.// close socket

137. close(socketfd);

138.

139.return (void*)0;

140.}

五、客户端测试代码

1.////////////////////////////////////////////////////////////////////////

//

2.// COPYRIGHT NOTICE

3.// Copyright (c) 2011, 华中科技大学 ticktick(版权声明)

4.// All rights reserved.

5.//

6./// @file main.c

7./// @brief tcp客户端测试代码

8.///

9./// 实现 tcp客户端测试

10.///

11./// @version 1.0

12./// @author lujun

13./// @E-mail lujun.hust@https://www.wendangku.net/doc/5411525006.html,

14./// @date 2011/08/21

15.//

16.//

17.// 修订说明:

18.////////////////////////////////////////////////////////////////////////

//

19.

20.#include

21.

22.#include "client.h"

23.

24.#define LOCAL_IP_STR "127.0.0.1"

25.#define DEST_IP_STR "192.201.0.8"

26.#define DEST_PORT 8000

27.

28.int main(int argc, char **argv)

29.{

30.int i =0;

31.

32. printf("tcp test start!\n");

33.

34.if( connect_server(DEST_IP_STR,DEST_PORT) != 0)

35. {

36.return -1;

37. }

38.

39. ServerPack sPack;

40. sPack.serverCMD = CMD_SAVE_USER_AGE;

41. https://www.wendangku.net/doc/5411525006.html,erage = 20;

42.

43.if( send_cmd(sPack) == -1 )

44. {

45. printf("send cmd fail!\n");

46. }

47.

48. getchar();

49. getchar();

50.

51. close_connect();

52.

53. printf("tcp test pass!\n");

54.

55.return 0;

56.}

六、服务器端测试代码

1.////////////////////////////////////////////////////////////////////////

//

2.// COPYRIGHT NOTICE

3.// Copyright (c) 2011, 华中科技大学 ticktick(版权声明)

4.// All rights reserved.

5.//

6./// @file main.c

7./// @brief tcp客户端代码

8.///

9./// 实现tcp服务器端测试的代码

10.///

11./// @version 1.0

12./// @author lujun

13./// @E-mail lujun.hust@https://www.wendangku.net/doc/5411525006.html,

14./// @date 2011/08/21

15.//

16.//

17.// 修订说明:

18.////////////////////////////////////////////////////////////////////////

//

19.

20.#include

21.

22.#include "server.h"

23.#include "serverIf.h"

24.

25.#define LOCAL_PORT 8000

26.

27.int main(int argc, char **argv)

28.{

29. printf("tcp test start!\n");

30.

31.if( open_port(LOCAL_PORT) != 0)

32. {

33.return -1;

34. }

35.

36. close_port();

37.

38. printf(" close port !\n");

39.

40.return 0;

41.}

七、总结和说明

本文后面的附件中有完整的代码,欢迎下载使用。编译方法,把代码文件夹都拷贝到linux下,在本代码文件夹的根目录下,运行make,即可生成对应的可执行文件。在运行测试程序的时候,请先执行server.out,然后执行client.out

相关文档