写在前面
在编程里,我们使用 Socket 来实现 TCP 或 UDP 的通信,Socket 是对它们的上层封装。虽然是不同的语言,但它们的 API 接口都遵循一致的逻辑。本篇主要是使用不同语言(C、Java 和 Dart),通过其 Socket API 来实现一个简单的 TCP 通信进行记录。
内容
API
这里主要罗列几种语言使用 Socket 时的几个基本 API,能够完成一个大致的流程。
C
在 C 语言的sys/socket.h头文件里定义了使用 Socket 的几个 API ,分别是:
int socket(int domain , int type , int protocol);
int bind(int sockfd , struct sockaddr *myaddr , socklen_t addrlen);
int listen(int sockfd , int backlog);
int accept(int sockfd , struct sockaddr *addr , socklen_t * addrlen);
int connect(int sockfd , struct sockaddr *serv_addr , socklen_t addrlen);
ssize_t write(int fd , const void * buf , size_t nbytes);
ssize_t read(int fd , void * buf , size_t nbytes);
int close(int fd);
不管是客户端还是服务端,C 语言里都是先使用 socket()进行创建。
Java
Java 里创建 Socket 的时候,客户端和服务端会使用不同的类,客户端使用的是 Socket类,服务端使用的是ServerSocket类
Socket
Socket()
public void connect(SocketAddress endpoint)
public InputStream getInputStream()
public OutputStream getOutputStream()
public synchronized void close()
ServerSocket
ServerSocket()
public void bind(SocketAddress endpoint)
public Socket accept()
- 监听连接的到来,并获取到一个新的 Socket,这个 Socket 就是客户端的操作对象
public void close()
因为服务端通过accept()拿到了操作客户端的对象,所以输入输出也就对应Socket的 API。
Dart
待续
代码示例
C
服务端
echo_sever.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 1024
void error_handling(char *message);
int main(int argc, char const *argv[])
{
int serv_sock;
int clnt_sock;
struct sockaddr_in serv_addr;
struct sockaddr_in clnt_addr;
socklen_t clnt_addr_size;
int str_len, i;
char message[]="hello world!";
if(argc != 2){
printf("Usage : %s <port>\n", argv[0]);
exit(1);
}
serv_sock = socket(PF_INET , SOCK_STREAM , 0);
if(serv_sock == -1){
error_handling("socket() error");
}
memset(&serv_addr , 0 , sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(atoi(argv[1]));
if(bind(serv_sock , (struct sockaddr*) &serv_addr , sizeof(serv_addr)) == -1){
error_handling("bind() error");
}
if(listen(serv_sock , 5) == -1){
error_handling("listen() error");
}
clnt_addr_size = sizeof(clnt_addr);
for (int i = 0; i < 5; i++)
{
clnt_sock = accept(serv_sock , (struct sockaddr*)&clnt_addr , &clnt_addr_size);
if(clnt_sock == -1){
error_handling("accept() error");
}else{
printf("Connected client %d \n" , i+1);
}
while((str_len = read(clnt_sock , message , BUF_SIZE)) != 0){
write(clnt_sock , message , str_len);
}
close(clnt_sock);
}
close(serv_sock);
return 0;
}
void error_handling(char *message){
fputs(message , stderr);
fputc('\n' , stderr);
exit(1);
}
客户端
echo_client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 1024
void error_handling(char *message);
int main(int argc, char const *argv[])
{
int sock;
struct sockaddr_in serv_addr;
char message[30];
int str_len;
if(argc != 3){
printf("Usage : %s <IP> <port>\n", argv[0]);
exit(1);
}
sock = socket(PF_INET , SOCK_STREAM , 0);
if(sock == -1){
error_handling("socket() error");
}
memset(&serv_addr , 0 , sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
serv_addr.sin_port = htons(atoi(argv[2]));
if(connect(sock , (struct sockaddr*)&serv_addr , sizeof(serv_addr)) == -1){
error_handling("connect() error");
}else{
puts("Connected............");
}
while(1){
fputs("Input message(Q to quit): " , stdout);
fgets(message , BUF_SIZE , stdin);
if(!strcmp(message , "q\n") || !strcmp(message , "Q\n")){
break;
}
write(sock , message , strlen(message));
str_len = read(sock , message , BUF_SIZE-1);
message[str_len] = 0;
printf("Message from server : %s \n", message);
}
close(sock);
return 0;
}
void error_handling(char *message){
fputs(message , stderr);
fputc('\n' , stderr);
exit(1);
}
Java
服务端
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(2000);
System.out.println("服务器准备就绪");
System.out.println("服务端信息 : " + serverSocket.getInetAddress() + " P : " + serverSocket.getLocalPort());
for (; ; ) {
Socket clientSocket = serverSocket.accept();
ClientHandler clientHandler = new ClientHandler(clientSocket);
clientHandler.start();
}
}
private static class ClientHandler extends Thread {
private Socket socket;
private boolean flag = true;
public ClientHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
super.run();
System.out.println("新客户端连接 : " + socket.getInetAddress() + " P : " + socket.getPort());
try {
PrintStream socketOutput = new PrintStream(socket.getOutputStream());
BufferedReader socketInput = new BufferedReader(new InputStreamReader(socket.getInputStream()));
do {
String str = socketInput.readLine();
if ("bye".equalsIgnoreCase(str)) {
flag = false;
socketOutput.println("bye");
} else {
System.out.println(str);
socketOutput.println("接收到的数据长度为 : " + str.length());
}
} while (flag);
socketInput.close();
socketOutput.close();
} catch (Exception e) {
System.out.println("连接异常断开");
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("客户端已关闭 : " + socket.getInetAddress() + " P : " + socket.getPort());
}
}
}
客户端
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket();
socket.setSoTimeout(3000);
socket.connect(new InetSocketAddress(Inet4Address.getLocalHost(), 2000), 3000);
System.out.println("已发送服务器连接");
System.out.println("客户端信息 : " + socket.getLocalAddress() + " P : " + socket.getLocalPort());
System.out.println("服务端信息 : " + socket.getInetAddress() + " P : " + socket.getPort());
try {
todo(socket);
} catch (Exception e) {
System.out.println("异常关闭");
}
socket.close();
socket.shutdownInput();
System.out.println("客户端已退出");
}
private static void todo(Socket client) throws IOException {
InputStream systemInputStream = System.in;
BufferedReader inputReader = new BufferedReader(new InputStreamReader(systemInputStream));
OutputStream outputStream = client.getOutputStream();
PrintStream socketPrintStream = new PrintStream(outputStream);
InputStream inputStream = client.getInputStream();
BufferedReader socketBufferedReader = new BufferedReader(new InputStreamReader(inputStream));
boolean flag = true;
do {
String str = inputReader.readLine();
socketPrintStream.println(str);
String echo = socketBufferedReader.readLine();
if ("bye".equalsIgnoreCase(echo)) {
flag = false;
} else {
System.out.println(echo);
}
} while (flag);
socketPrintStream.close();
socketBufferedReader.close();
}
}
Dart
待续
参考
《TCP/IP网络编程》
|