【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
本文中的代码是我在学习linux套接字编程时写的,运行环境为RedHat,编译环境为G++
测试环境有两台linux虚拟机,地址分别设为192.168.8.123和192.168.8.99
其中,192.168.8.123上运行了客户端,其源码(client.cpp)为
#include<sys/types.h> //data types
#include<sys/socket.h> //main sockets header
#include<stdio.h> //standard buffered input/output
#include<netinet/in.h> //Internet address family
#include<arpa/inet.h> //definitions for internet operations
#include<unistd.h> //standard symbolic constants and types
#include<stdlib.h> //standard library definitions
#include<string.h> //string operions
int main()
{
struct sockaddr_in address;
//#include<netinet/in.h>
//struct sockaddr_in includes at least the following member:
// sa_family_t sin_family AF_INET
// in_port_t sin_port Port number
// struct in_addr sin_addr IP address
//The sockaddr_in structure is used to store addresses
//for the Internet address family
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("192.168.8.99");
address.sin_port = htons(9734);
int len = sizeof(address);
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
//#include<sys/types.h>
//#include<sys/socket.h>
//int socket(int domain, int type, int protocal);
//0.socket() creates an endpoint for communication and returns a descriptor
//1.[domain] argument specifies a communication domain
// Name Purpose
// AF_UNIX Local communication
// AF_INET IPv4 Internet protocols
//2.socket has the indicated [type] which specifies the communication semantics
// SOCK_STREAM: Provides sequenced, reliable, two-way,
// connection-based byte streams
//3.The [protocol] specifies a particular protocol to be used with the socket.
// Normally only a single protocol exists to support a particular socket
// type within a given protocol family, in which case protocol can be
// specified as 0
int result = connect(sockfd, (struct sockaddr *)&address, len);
//#include<sys/types.h>
//#include<sys/socket.h>
//int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//0.The connect() system call connects the socket referred to by the file
// descriptor [sockfd] to the address specified by [addr]. The [addrlen]
// argument specifies the size of [addr]
//1.If the connection or binding succeeds, zero is returned.
// On error, -1 is returned, and [errno] is set appropriately.
if(result == -1)
{
perror("oops: client");
//#include<stdio.h>
//void perror(const char *s);
//0.The routine perror() produces a message on the standard
// error output, describing the last error encountered
// during a call to a system or library function.
exit(1);
//#include<stdlib.h>
//void exit(int status);
//0.The exit() function causes normal process termination
// and the value of [status & 0377] is returned to the parent
}
char input[100];
printf("Please Enter Your Input: ");
fgets(input, 100, stdin);
for(int counter = 0; counter < strlen(input); counter++)
{
if(input[counter] == '\n')
{
input[counter] = '\0';
}
}
write(sockfd, input, 100);
//#include<unistd.h>
//ssize_t write(int fd, const void *buf, size_t count);
//0.write() writes up to [count] bytes from the buffer pointed to the
// file referred by the file descriptor [fd]
//1.On success, the number of bytes written is returned.
// On error, -1 is returned, and [errno] is set appropriately.
printf("Send Input: %s\n", input);
char output[100];
read(sockfd, output, 100);
//#include<unistd.h>
//ssize_t read(int fd, void *buf, size_t count);
//0.read() attempts to read up to [count] bytes from file descriptor
// [fd] into the buffer starting at [buf]
//1.On success, the number of bytes read is returned, and the file position
// is advanced by this number.
// On error, -1 is returned, and [errno] is set appropriately.
printf("Receive Output: %s\n", output);
close(sockfd);
//#include<unistd.h>
//int close(int fd);
//0.close() closes a file descriptor, so that it no longer refers to any
// file and may be reused. Any record locks held on the file it was
// associated with, and owned by the process, are removed.
//1.close() returns zero on success.
// On error, -1 is returned, and [errno] is set appropriately.
exit(0);
}
192.168.8.99上运行了服务器,其源码(server.cpp)为
#include<sys/types.h>
#include<sys/socket.h>
#include<stdio.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int server_sockfd, client_sockfd;
socklen_t server_len, client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("192.168.8.99");
server_address.sin_port = htons(9734);
server_len = sizeof(server_address);
bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
//#include<sys/types.h>
//#include<sys/socket.h>
//int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//0.When a socket is create with socket(), it exists in a name space
// (address family) but has no address assigned to it. bind() assigns
// the address specified to by [addr] to the socket referred to by the
// file descriptior [sockfd]. [addrlen] specifies the size, in bytes,
// of the address structure pointed to by [addr].
// Traditionally, this operation is called "assigning a name to a socket"
//1.On success, zero is returned.
// On error, -1 is returned, and [errno] is set appropriately.
listen(server_sockfd, 5);
//#include<sys/types.h>
//#include<sys/socket.h>
//int listen(int sockfd, int backlog)
//0.listen() marks the socket referred to by [sockfd] as a passive socket,
// that is, as a socket that will be used to accept incoming connection
// requests using accept()
//1.The [sockfd] argument is a file descriptor that refers to a socket of
// type SOCK_STREAM or SOCK_SEQPACKET
//2.The [backlog] argument defines the maximum length to which queue of
// pending connections for [sockfd] may grow
//3.On success, zero is returned.
// On error, -1 is returned, and [errno] is set appropriately.
while(1)
{
printf("server waiting\n");
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd,
(struct sockaddr *)&client_address, &client_len);
//#include<sys/types.h>
//#include<sys/socket.h>
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//0.The accept() system call is used with connection-based socket types
// (SOCK_STREAM, SOCK_SEQPACKET). It extracts the first connection
// request on the queue of pending connections for the listening socket,
// [sockfd], creates a new connected socket, and returns a new file
// descriptor referring to that socket. The newly created socket is
// not in the listening state. The original socket [sockfd] is
// unaffected by this call.
char input[100];
read(client_sockfd, input, 100);
printf("Receive Input: %s\n", input);
char output[100] = "[RETURN] ";
strcat(output, input);
write(client_sockfd, output, 100);
printf("Send Output: %s\n", output);
close(client_sockfd);
}
}
编译这两个文件,分别输入命令
g++ client.cpp -o client
g++ server.cpp -o server
运行这两个程序前,先要关闭linux的防火墙。
方法为在su权限下输入命令
iptables -F
先在198.168.8.99上运行服务器server,然后再在192.168.8.123上运行client。在客户端输入字符串Hello World!,服务器端收到了这个字符串后会在前面加入字符串“[RETURN] ”然后返回给客户端。效果如下图所示:
server端
client端
关于这两段代码,需要注意两点:
1)因为TCP连接在最后有一个TIME_WAIT状态,因此在server程序停掉后,要隔一分钟打开,才能用client重新连接上
2)G++的检查比GCC要严格,服务器server.cpp代码中的server_len和client_len,不能声明为int类型,而要声明为socklen_t类型
END
来源:oschina
链接:https://my.oschina.net/u/1425762/blog/307976