TCP网络编程示例

其他知识:Linux与Windows下的网络编程区别

TCP通信知识

  1. 使用TCP通信时常使用的函数和流程
1
2
3
4
5
6
7
8
TCP服务端流程:			TCP客户端流程:
创建会话socket 创建会话socket
绑定端口bind 连接建立connect
监听端口listen
请求accept
接收信息recv 接收信息recv
发送消息send 发送消息send
关闭连接close 关闭连接close
  1. 创建TCP连接时,主动发起连接的叫客户端,被动响应连接的叫服务器。

  2. 套接字由三个参数构成:IP地址,端口号,传输层协议。这三个参数用以区分不同应用程序进程间的网络通信与连接。

  3. family指明了协议族/域,通常AF_INET、AF_INET6、AF_LOCAL等。AF_INET是IPv4协议,AF_INET6是IPv4协议;

  4. type是套接口类型,主要SOCK_STREAM、SOCK_DGRAM、SOCK_RAW,SOCK_STREAM是TCP协议,SOCK_DGRAM是UDP协议;

客户端和服务端通用函数

  1. int socket(int family, int type, int protocol)
    (地址协议, 连接类型, 一般为0)
    返回值:成功就返回新创建的套接字的描述符,失败返回-1;

  2. int recv( SOCKET s, char *buf, int len, int flags)
    (套接字描述符, 存放接收数据的缓冲区, 该缓冲区长度, 0)
    返回值:成功返回接收的字节数,为0则对方关闭了连接,失败返回-1,并设置errno;

  3. int send( SOCKET s, const char *buf, int len, int flags)
    (套接字描述符, 存放发送数据的缓冲区, 发送数据的字节数, 0)
    返回值:成功返回发送的字节数,为0则对方关闭了连接,失败返回-1,并设置errno;

  4. int close(int fd)
    (fd为要关闭的文件描述符)
    返回值:成功为0,失败返回-1,并设置errno;

客户端或服务端独有函数

  1. int connect(int sockfd, const struct sockaddr *sockaddr, int addrlen)
    (套接字描述符, 套接字地址结构的指针, 该结构的大小)
    返回值:成功返回0,失败返回-1,并设置errno;

  2. int bind(int sockfd, const struct *server_addr, int addrlen)
    (套接字描述符, 套接字地址结构的指针, 该结构的大小)
    返回值:成功返回0,失败返回-1,并设置errno;

  3. int listen(int sockfd, int backlog)
    (套接字描述符, 最大连接数)
    返回值:成功返回0,失败返回-1,并设置errno;

  4. accept(SOCKET s, const struct sockaddr client_addr, int addrlen)
    (套接字描述符, 套接字地址结构的指针, 指针类型该结构的大小)
    返回值是一个新的套接字描述符,它代表的是和客户端的新的连接,可以把它理解成是一个客户端的socket,这个socket包含的是客户端的ip和port信息 。(当然这个new_socket会从sockfd中继承 服务器的ip和port信息,两种都有了),而参数中的SOCKET s包含的是服务器的ip和port信息 。

Linux下服务端程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
int fd, new_fd, struct_len, numbytes,i;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
char buff[BUFSIZ];
struct_len = sizeof(struct sockaddr_in);

// 指定协议,端口,地址
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8000);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero), 8);

// 创建套接字,绑定,监听
fd = socket(AF_INET, SOCK_STREAM, 0);
bind(fd, (struct sockaddr *)&server_addr, struct_len);
listen(fd, 10);

new_fd = accept(fd, (struct sockaddr *)&client_addr, &struct_len);
printf("Get the Client.\n");

// 缓冲区大小
numbytes = send(new_fd, "Welcome To My Server\n", 21, 0);

// 如果连接后客户端退出那么服务端也将退出
while((numbytes = recv(new_fd, buff, BUFSIZ, 0)) > 0)
{
buff[numbytes] = '\0';
printf("%s\n", buff);
if(send(new_fd, buff, numbytes, 0) < 0)
{
perror("Error"); // 输出错误。先输出字符串 Error,后跟一个冒号,然后是一个空格。
return 1;
}
}

close(new_fd);
close(fd);

return 0;
}

Linux下客户端程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#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 <arpa/inet.h>

int main(int argc,char *argv[])
{
int sockfd, numbytes;
char buf[BUFSIZ];
struct sockaddr_in sockaddr;

// 指定协议,端口,地址
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(8000);
sockaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
//sockaddr.sin_addr.s_addr=inet_addr("192.168.1.1");
bzero(&(sockaddr.sin_zero), 8);

// 创建套接字
sockfd = socket(AF_INET,SOCK_STREAM,0);

// 连接服务端
connect(sockfd,(struct sockaddr*)&sockaddr, sizeof(struct sockaddr));

// 接收服务端的欢迎信息
numbytes = recv(sockfd, buf, BUFSIZ, 0); // 返回copy的字节数,(套接字, 存放接收的缓冲区, 缓冲区长度, 0)
buf[numbytes] = '\0'; // 清空缓冲区
printf("%s", buf);

// 循环发送接收信息
while(1)
{
printf("Input:"); // 提示输入
scanf("%s", buf); // 接收输入
numbytes = send(sockfd, buf, strlen(buf), 0); // 发送输入的内容
numbytes = recv(sockfd,buf,BUFSIZ,0); // 接收传回的内容
buf[numbytes] = '\0'; // 清空缓冲区
printf("received:%s\n", buf); // 打印发出的内容
}

close(sockfd); // 关闭套接字

return 0;
}